【问题标题】:What is the difference between <- and "let" inside do blocks? [duplicate]do 块中的 <- 和 "let" 有什么区别? [复制]
【发布时间】:2016-02-29 12:23:48
【问题描述】:

我不明白什么时候必须使用let,什么时候必须使用&lt;- 绑定。

【问题讨论】:

  • 详细了解let 的实际含义以及&lt;- 的实际作用。而且,可能是关于 do 符号。

标签: haskell frege


【解决方案1】:

let 为函数调用的结果命名。

&lt;- 将当前 monad 中的 monadic 操作的结果绑定到一个名称。

它们完全不同。使用 let 获取 monad 之外的函数的结果,即普通的纯函数。将&lt;- 用于任何单子,因为它“解包”单子结果并让您获得其中的值。

例如:

假设一个具有以下签名的 IO 函数

frobnicate :: String -> IO Bool

纯函数

dothing :: Bool -> Bool

我们可以这样做

main :: IO ()
main = do
  x <- frobnicate "Hello"
  let y = frobnicate "Hello"
  -- z <- dothing x
  let z = dothing x
  return ()

我们知道x :: Bool,因为Bool已经为我们从IO操作结果中提取出来(操作运行,结果称为x,所以我们以后可以使用它)。

我们也知道y :: IO Bool - 该操作尚未运行,它是潜在 未来的 IO 操作。所以我们可以对y 做的唯一有用的事情是稍后运行它,绑定结果并以这种方式获取Bool,但在let 之后Bool 甚至还不存在。

第三行被注释掉,因为它不会编译 - 你不能对不在相关 monad 中的操作执行 monadic 绑定。 dothing 不会返回 IO 任何内容,因此您无法将其绑定到 IO () 函数中。

第四行很简单——zdothing x 的结果,其中x 是之前运行frobnicate "Hello" 解包后的值。

所有这些只是下面“真正的” monad 操作的语法糖,因此可以扩展(没有注释掉的部分)类似于

main = frobnicate "Hello" >>= (\x -> let y = frobnicate "Hello"
                                         z = dothing x
                                      in return ())

这个例子当然毫无意义,但希望它能说明let&lt;-do 表示法中的不同之处。

TL;DR:使用 &lt;- 为一元操作的结果命名,let 为其他所有内容命名。

【讨论】:

    【解决方案2】:

    &lt;-&gt;&gt;= (bind) 其中 letfmapdo 块中。

    here中窃取示例:

    do x1 <- action1 x0
       x2 <- action2 x1
       action3 x1 x2
    
    -- is equivalent to:
    action1 x0 >>= \ x1 -> action2 x1 >>= \ x2 -> action3 x1 x2
    

    action1action2action3 都返回某种单子,比如:

    action1 :: (Monad m) => a -> m b
    action2 :: (Monad m) => b -> m c
    action3 :: (Monad m) => b -> c -> m d
    

    您可以这样重写 let 绑定:

    -- assume action1 & action3 are the same
    -- but action2 is thus:
    action2 :: b -> c
    
    do
        x1 <- action1 x0
        let x2 = action2 x1
        action3 x1 x2
    
    do
        x1 <- action1 x0
        x2 <- return & action2 x1
        action3 x1 x2
    
    -- of course it doesn't make sense to call action2
    -- an action anymore, it's just a pure function.
    

    【讨论】:

      【解决方案3】:

      一个很好的例子来可视化&lt;- 所做的事情:

      do
          a <- ['a'..'z']
          b <- [1..3]
          pure (a,b)
      

      您可以在try.frege-lang.org 的在线 REPL 中尝试此操作 (您可以将其输入为一行:

      do { a <- ['a'..'z']; b <- [1..3]; pure (a,b) }
      

      【讨论】:

        猜你喜欢
        • 2019-06-25
        • 1970-01-01
        • 2018-12-22
        • 2013-09-22
        • 1970-01-01
        • 2015-08-12
        • 2022-07-21
        相关资源
        最近更新 更多