【问题标题】:>> operator - poor man's loop in Haskell?>> 运算符 - Haskell 中的穷人循环?
【发布时间】:2015-08-06 06:17:47
【问题描述】:

我不知道 Haskell,我只是想玩弄它来学习它。我试图理解 io、monads 等,并在解释器中写了这个(GHCi,版本 7.10.2,WinGHCI):

Prelude> [1,1] >> "ok"
"okok"
Prelude> [1,1,1] >> "ok"
"okokok"
Prelude> [1..10] >> "ok"
"okokokokokokokokokok"
Prelude> [1] >> "ok" >> [1] >> "ok"
"okok"
Prelude> [1,2] >> "ok" >> [1,2] >> "ok"
"okokokokokokokok"
Prelude> [1..10] >> [1..10]
[1,2,3,4,5,6,7,8,9,10,1,2,3,4,5,6,7,8,9,10,1,2,3,4,5,6,7,8,9,10,1,2,3,4,5,6,7,8,9,10,1,2,3,4,5,6,7,8,9,10,1,2,3,4,5,6,7,8,9,10,1,2,3,4,5,6,7,8,9,10,1,2,3,4,5,6,7,8,9,10,1,2,3,4,5,6,7,8,9,10,1,2,3,4,5,6,7,8,9,10]

愿意解释一下吗?为什么列表中的元素数量会影响写入“ok”的次数(或者在最后一种情况下,会影响写入数组的次数)? >> 运算符不应该这样做,是吗?

【问题讨论】:

    标签: list haskell monads


    【解决方案1】:

    首先请注意,这与IO 无关。它与单子有关,但与一个非常具体的单子有关:列表单子。

    instance Monad [] where
      return x = [x]
      f >>= xs = concat $ map f xs   -- aka `(>>=) = concatMap`.
    

    最好了解 列表推导,它基本上是语法糖†:

    [ result x y z | x <- bla, y <- foo x, z <- bar ]
    

    翻译成

    bla >>=
       \x -> foo x >>=
                \y -> bar >>=
                         \z -> return (result x y z)
    

    现在,a&gt;&gt;b 只是a &gt;&gt;= \_ -&gt; b 的捷径,即它忽略了包含在 LHS 单子动作中的值,但“假装”在 RHS 中使用它们。所以,[1,1,1] &gt;&gt; "ok" 是一样的

    [ "ok" | _ <- [1,1,1] ]
    

    至少几乎...实际上这与[1,1,1] &gt;&gt; return "ok" 相同,即&gt;&gt; ["ok"],它将给出

    ["ok", "ok", "ok"]
    

    如果你省略了单例return,每个"ok" 将不会被包装在一个列表中并且将它们连接起来,而是将字符串本身全部通过一元绑定连接起来。这就是您获得"okokok" 的方式。


    †等效的默认实现实际上有点不同,但是使用 -XMonadComprehensions 扩展名,列表推导确实可以这样工作。

    【讨论】:

    • 所以我无意中使用了列表单子,而不是列表?我猜那行代码中的解释器甚至不会接受一个真实的列表?
    • @user3355020:确定这是一个列表,和任何列表一样真实。谈论 list monad 仅仅意味着我们专注于列表的一个特定特性/属性。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-09-08
    • 1970-01-01
    • 1970-01-01
    • 2022-01-04
    • 1970-01-01
    相关资源
    最近更新 更多