在Haskell中,使用和不使用let有什么区别?

use*_*939 8 haskell

有人告诉我Haskell没有变量而是绑定.现在这意味着什么,我总是想知道在编写这些绑定时有什么区别,如下所示:

x = 5
Run Code Online (Sandbox Code Playgroud)

let x = 5
Run Code Online (Sandbox Code Playgroud)

这有什么区别?

还有一个后续问题:我是否通过这样做创建变量?如果x不是变量,它是什么?

Die*_*Epp 14

唯一真正的区别在于它们发生的地方.

-- At top (file) level or in "where" blocks, omit "let".
x = 5

f1 y = x + y
  where
    x = 5

-- Inside expressions or do-blocks, "let" is required.
f2 y = let x = 5
       in x + y

f3 y = do someAction
          let x = 5
          return (x + y)
Run Code Online (Sandbox Code Playgroud)

在所有情况下,x都是变量.但是,您无法更改(变更)变量的值.

在GHCi提示符中,您似乎更改了变量的值,但您不能.您只能创建具有相同名称的新变量,旧变量仍然存在.

Prelude> let x = 3
Prelude> let f y = x + y
Prelude> let x = 10
Prelude> f 1
4

如果你真的改变了价值x,那么f 1就是11.

  • 交互式解释器中的连续绑定更像是嵌套的`let`表达式的语法糖.使用上面的例子,它类似于`let x = 3 in let fy = x + y in let x = 10 in f 1`.在创建一个名为`x`的新变量并将其赋值为10之前,`f`的值已被修复,当你最终调用`f`时,`x`的值来自`f`的范围.*定义*,而不是***. (5认同)
  • 可能值得一提的是,`ghci`现在也可以省略`let`. (3认同)

Chr*_*tin 6

Haskell有变量,但我们说它们是绑定而不是分配.这些是非常相似的概念,但它们是否支持多重赋值不同--Haskell不支持.

do let x = 1
   let x = 2
   print x     -- prints "2"
Run Code Online (Sandbox Code Playgroud)

当我们说它没有时,我们的意思是所有变量都是静态绑定的.这意味着只要有对变量的引用,您就可以通过代码查找并找到它所引用的一个绑定.

以Python为例,它有多个赋值.

def f(a):
    x = 1          # first assignment
    x = 2          # second assignment

    for i in a:
        x = i      # third assignment
        print x 

    print x
Run Code Online (Sandbox Code Playgroud)

在上面的示例中,x分配了三个位置.当我们x在最后一行引用时,我们可以2从第二个赋值中获取,或者我们可以a从循环中的赋值中获取其中一个值.第三次任务是否发生取决于是否a为空.

那么让我们看看Haskell中的类似代码:

f a = do let x = 1                    -- first binding
         let x = 2                    -- second binding
         for_ a $ \i -> do let x = i  -- third binding
                           print x
         print x
Run Code Online (Sandbox Code Playgroud)

此输出的最后一行始终为"2",因为在代码中的那一点,第二个绑定是x在该范围内接收的最内层绑定.如果我们要引入另一个更紧密的绑定,那么我们可以改变:

f a = do let x = 1                    -- first binding
         let x = 2                    -- second binding
         for_ a $ \i -> do let x = i  -- third binding
                           print x
         let x = head a               -- fourth binding
         print x
Run Code Online (Sandbox Code Playgroud)

但是,我们永远不能做的是引入关于某些绑定指的是什么的含糊不清.