【问题标题】:Haskell Monadic formsHaskell 单子形式
【发布时间】:2011-07-06 15:57:01
【问题描述】:

一个简单的问题: 给定定义,(来自 Haskell SOE)

   do x — el; el\ ...; en 
    => el »= \x — do e2\ ...; en 

和:

do let decllist; el\...; en 
=> let decllist in do e2\ ...; en 

看来这两个构造是一样的:

do let x = e1
   e2

do x <- e1
   e2

都计算 e1,将其绑定到 e2,然后计算 e2。

是吗?

【问题讨论】:

    标签: haskell monads


    【解决方案1】:

    让我们在Maybe monad 中做一个简单的例子:

    foo = do
            let x = Just 1
            return x
    

    bar = do
            x <- Just 1
            return x
    

    对两者都进行脱糖,我们得到

    foo = let x = Just 1 in return x    -- do notation desugaring
        = return (Just 1)               -- let
        = Just (Just 1)                 -- definition of return for the Maybe monad
    
    bar = let ok x = return x in Just 1 >>= ok   -- do notation desugaring
        = let ok x = return x in ok 1   -- definition of >>= for the Maybe monad
        = return 1                      -- definiton of ok
        = Just 1                        -- definition of return for the Maybe monad
    

    作为参考,我使用的是translation from section 3.14 of the Haskell 2010 Report

    【讨论】:

      【解决方案2】:

      不,它们不一样。例如,

      do let x = getLine
         print x
      

      翻译成

      let x = getLine in print x
      

      这是一个类型错误,因为x 将具有IO String 类型。我们要求打印计算本身,而不是其结果。


      do x <- getLine
         print x
      

      翻译成

      getLine >>= \x -> print x
      

      这里x被绑定为计算结果,它的类型是String,所以这个类型检查。


      do-notation 中,let 只是像往常一样将值绑定到名称,而&lt;- 用于执行单子绑定,即将名称绑定到 result计算。

      【讨论】:

        【解决方案3】:

        假设e1Monad m =&gt; m a 类型的计算,那么let x = e1x &lt;- e1 的含义有些不同。

        let 版本中,当您在do 表达式中使用x 时,您处理的是Monad m =&gt; m a 类型的值。

        在另一个版本中,当您在 do 表达式中使用 x 时,您处理的是 a 类型的值(因为 do-notation 隐式处理对 monad 的映射)。

        例如:

        e :: IO Int
        f :: Int -> Int
        
        -- the following will result in a type error, since f operates on `Int`, not `IO Int`:
        g = do let x = e
               return $ f x
        
        -- the following will work:
        g' = do x <- e
                return $ f x
        

        【讨论】:

        • 谢谢。单子让我想起了量子力学——“如果你认为你理解它们,那你就没有”! :-)
        • 在我的例子中; e::Int,所以“let”会起作用,而不是箭头 - 是吗?
        • @Guthrie 哦,如果e :: Int,那么你确实需要使用let
        【解决方案4】:

        没有。 x &lt;- e1 转换为 e1 &gt;&gt;= \x -&gt;,一个不完整的表达式; let 表达式只是一个普通的let。或者你在问let(&gt;&gt;=) 是不是同一个东西?它们不是:(&gt;&gt;=) 将 monad 包裹的东西暴露给一个函数,该函数必须产生包裹在 monad 中的东西。换句话说,对于x &lt;- e1,对于某些ae1 的类型必须是IO a,但对于let x = e1e1 的类型只是a;在这两种情况下,x 的类型都是 a

        【讨论】:

        • letdo 表达式中不仅仅是一个普通的let 表达式。这是一个let 声明(Haskell 2010 报告,第 3.14 节)。 let 语句脱糖成 let 表达式,但它本身不是 let 表达式。同样e1 &gt;&gt;= \x -&gt; 毫无意义。最好只看报告中的翻译规则。
        猜你喜欢
        • 2021-08-27
        • 1970-01-01
        • 1970-01-01
        • 2017-05-08
        • 2021-12-24
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多