【问题标题】:Why do you need let keyword in do block?为什么在 do 块中需要 let 关键字?
【发布时间】:2017-03-31 13:10:01
【问题描述】:

letdo 块中的原因是什么。

-- codeblock A
main = do
  let a = 0
  let f a = a + 1
  let b = f 0
  print (a,b)

-- codeblock B
main = do
  a = 0
  f a = a + 1
  b = f 0
  print (a,b)

假设所有let 没有in 后面必须跟=(这是真的吗?)

编译器应该能够将 let= 和预处理/脱糖 codeblock B 隐含到 codeblock A

在这种情况下使用let 似乎是不必要的,就像你可以写codeblock C 但选择写codeblock D

-- codeblock C
main = do
  print (a,b)

a = 0
f a = a + 1
b = f 0

-- codeblock D
main = do
  print (a,b)

function  a = 0
function  f a = a + 1
function  b = f 0

为了澄清我的假设不包括let,后面跟着in,应该保持不变。

-- codeblock E
main = do
  a = 0
  f a = a + 1
  b = f 0
  c = let d = 1 
          e = 1
      in d + e
  print (a,b,c)

【问题讨论】:

    标签: haskell let


    【解决方案1】:

    我不知道为什么要这样做,但我可以想象到一个原因:它允许您指定哪些绑定应该按顺序建立,哪些同时建立,这在阴影的情况下很重要。

    例如,假设你的建议被执行,然后考虑:

    foo :: [Int]
    foo = do
      x <- return [1]
      y = 0:x
      x = [1..5]
      y
    

    有两种合理的方法可以脱糖:

    foo1 :: [Int]
    foo1 = do
      x <- return [1]
      let y = 0:x
      let x = [1..5]
      y
    
    foo2 :: [Int]
    foo2 = do
      x <- return [1]
      let y = 0:x
          x = [1..5]
      y
    

    foo1 计算结果为 [0,1]foo2 计算结果为 [0,1,2,3,4,5]。当然,这是一种奇怪的代码编写方式,但 let 必须是明确的这一事实意味着您的意图没有歧义。

    正如 chi 在 cmets 中所指出的,阴影并不是您可能需要明确说明 let 绑定如何分组的唯一原因:一个函数定义可能需要多个方程,以匹配多个参数模式。

    【讨论】:

    • 我想补充一点,这不仅仅是关于阴影。使用let,您可以在do-block 中定义本地函数。虽然本地函数的 w/o let 语法可能会变得丑陋。
    • 相关:一个函数定义可能跨越多个方程。比较:do ... ; let { f (K1 x) = ... ; f (K2 x) = ... } ; ...do ... ; let f (K1 x) = ... ; let f (K2 x) = ... ; ...(阴影)
    【解决方案2】:

    支持let 的一个论点是它在do 块中更加突出,否则这些块可能会充满各种类似单子赋值的运算符(想想用operators defined in lens 填充的东西)。

    do
      p1.x += delta             -- (+=) is a custom operator
      p2.y -= delta             -- (-=) is a custom operator
      let delta' = delta*delta
      p3 .= Point delta' delta' -- (.=) is a custom operator
    

    由于let,在这里我可以轻松区分用于抽象delta' 和实际一元代码的语法糖。

    【讨论】:

    • 你能覆盖运算符(=) 吗?如果不是,您会知道 delta' 是一个 let 绑定(不太可区分,但仍然可以)。如果是,您只需回答我的问题。
    • @wizzup,不,您不能覆盖 =。它根本不是运算符,而是原始语法。我认为关键是有些运算符看起来很相似,让人感到困惑。
    猜你喜欢
    • 2020-02-03
    • 1970-01-01
    • 1970-01-01
    • 2020-05-20
    • 2012-03-08
    • 2014-05-29
    • 2016-07-27
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多