繁体   English   中英

在Haskell中使用“ let”的功能纯度

[英]Functional Purity using 'let' in Haskell

在学习Haskell的过程中,我了解它是一种纯粹的功能语言。 我很难理解为什么let陈述不会违反纯洁。

例如(在ghci中):

Prelude> let e = exp 1
Prelude> e
2.718281828459045
Prelude> let e = 2
Prelude> e
2

我的第二个let语句不会产生副作用吗? 还是第二个let语句重新闭合?

第二个lete创建一个新的绑定,该绑定遮盖了现有变量。 它不会修改e 您可以使用以下方法轻松检查:

Prelude> let e = 1
Prelude> let f () = "e is now " ++ show e
Prelude> f ()
"e is now 1"
Prelude> let e = 2
Prelude> e
2
Prelude> f ()
"e is now 1"
Prelude> 

let引入一个具有单个不可更改值的新局部变量,它的局部作用域比周围的任何定义都多,因此例如:

*Main> (let length = 2 in show length) ++ ' ':show (length "Hello")
"2 5"

在这里,第一个length的值是2,但范围仅限于方括号。 在括号之外, length表示它一直以来的含义。 没有进行任何编辑,只引入了一个更多的局部变量,该变量恰好与另一个作​​用域的名称相同。 让我们让ghci疯狂,省去括号并尝试使length成为数字和函数:

*Main> let length = 2 in show length ++ ' ':show (length "Hello")

<interactive>:1:14:
    No instance for (Num ([Char] -> a0))
      arising from the literal `2'
    Possible fix: add an instance declaration for (Num ([Char] -> a0))
    In the expression: 2
    In an equation for `length': length = 2
    In the expression:
      let length = 2 in show length ++ ' ' : show (length "Hello")

<interactive>:1:19:
    No instance for (Show ([Char] -> a0))

      arising from a use of `show'
    Possible fix: add an instance declaration for (Show ([Char] -> a0))
    In the first argument of `(++)', namely `show length'
    In the expression: show length ++ ' ' : show (length "Hello")
    In the expression:
      let length = 2 in show length ++ ' ' : show (length "Hello")

这是您的示例:

*Main> let e = exp 1 in show e ++ " " ++ let e = 2 in show e
"2.718281828459045 2"

我将添加方括号以强调范围:

*Main> let e = exp 1 in (show e ++ " " ++ (let e = 2 in (show e)))
"2.718281828459045 2"

第一个e被隐藏而不是被编辑。 参照透明性得到保留,但是绝对不明智,因为它很难遵循。


现在,秘密地,交互式提示有点像IO monad中的一个大do块,所以让我们看一下:

testdo = do
  let e = exp 1
  print e
  let e = 2
  print e

现在,我不得不承认,这看起来很像破坏参照透明性,但请记住,这看起来也确实如此:

testWrite = do
   writeFile "test.txt" "Hello Mum"
   xs <- readFile "test.txt"
   print xs
   writeFile "test.txt" "Yo all"
   xs <- readFile "test.txt"
   print xs

现在,在什么意义上我们已经获得了参照透明性? xs显然是指两个不同的字符串。 那么,这是什么do记号实际上意味着什么呢? 这是语法糖

testWrite = writeFile "test.txt" "Hello Mum"
         >> readFile "test.txt" 
         >>= (\xs -> print xs 
         >> writeFile "test.txt" "Yo all"
         >> readFile "test.txt"
         >>= (\xs -> print xs))

现在,更清楚的是分配看起来又只是局部作用域。 您大概很高兴做

increment :: [Int] -> [Int]
increment = \x -> map (\x -> x+1) x

哪个在做同样的事情。


摘要
似乎只是分配了一个新的本地范围。 ew 如果您经常使用此功能,则会很不清楚代码的含义。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM