【问题标题】:Trying to exercise with the Cont monad. Syntax issue尝试使用 Cont monad 进行锻炼。语法问题
【发布时间】:2015-11-09 07:29:18
【问题描述】:

经过一些研究([1]、[2]、[3] 等),我正在尝试通过自己尝试一些示例来完成延续单子的工作。

[1] 的第二个答案建议使用延续来表达阶乘。我的解决方案如下:

Cont ($ (fact 0)) = return 1
Cont ($ (fact n)) = Cont ($ (fact (n-1))) >>= (\x -> Cont ($ (n*x)))

我在纸上做了一些模拟,解决方案应该是正确的。

但是我无法让它被 GHC 消化。当然我重命名了fact函数,但还是不开心。

我最近的尝试是https://gist.github.com/Muzietto/595bef1815ddf375129d 并一如既往地提供parse error in pattern \c -> .....

谁能建议这些定义的运行实现?

[1]How and why does the Haskell Cont monad work?

[2]http://hackage.haskell.org/package/mtl-1.1.0.2/docs/Control-Monad-Cont.html

[3]https://wiki.haskell.org/MonadCont_under_the_hood

【问题讨论】:

  • 首先:要点本身很好,但是你为什么不在这里复制和粘贴代码 - 这对我们在这里提供帮助很方便 - 接下来我认为你的类型不匹配(或者我猜你想做什么是错的) - 你是否尝试过仅使用 continuation-passing-style 来解决这个问题(你并不完全需要 monad/Cont-wrapper 来理解该技术)?
  • @carsten - 我的这个尝试确实源于一个完美运行的 CPS 实施,绝对是微不足道的。我相信很明显这个问题的全部意义在于使用 monad,尤其是它的 bind 函数。

标签: haskell monads continuations


【解决方案1】:

首先,您不能以发布的方式定义函数,原因与您无法实现前驱函数的原因相同,如下所示:

1 + (predecessor x) = x

函数只能通过以下形式的方程来定义

f pattern1 .. patternK = expression

请注意,f 必须在顶层找到。

对于使用 continuation monad 的阶乘函数,您可以按如下方式简化您的尝试:

fact :: Int -> Cont r Int
-- Your own code:
-- Cont ($ (fact 0)) = return 1
fact 0 = return 1
-- Cont ($ (fact n)) = Cont ($ (fact (n-1))) >>= (\x -> Cont ($ (n*x)))
fact n = fact (n-1) >>= \x -> return (n*x)

-- the "real" factorial function, without monads
factorial :: Int -> Int
factorial n = runCont (fact n) id

注意,上面的return (n*x)确实是Cont ($ (n*x)),但我认为前者的可读性更好,也是因为它没有破坏抽象。事实上,一旦按上述方式编写,它就可以在 任何 monad 中工作。

或者,使用do 表示法。

fact :: Int -> Cont r Int
fact 0 = return 1
fact n = do
   x <- fact (n-1)
   return (n*x)

或者使用仿函数操作符:

fact :: Int -> Cont r Int
fact 0 = return 1
fact n = (n*) <$> fact (n-1)

【讨论】:

  • 谢谢!我怀疑我在我的代码中做了一些非 Haskellian 的事情 :-) 我热衷于感受“绑定”,希望将抽象带到更高的层次。我感谢您的回答的彻底性和完整性。函子版本令人兴奋。得花点时间考虑一下这个 fmap。
  • @Muzietto Monads 必须与其函子实例“兼容”,因为它们必须满足法律fmap f x = x &gt;&gt;= (return . f)。基本上非正式地,如果你从 monad (&gt;&gt;=) 中得到一些东西,应用一些 f,然后用 return 将它放回 monad,结果应该与 fmap f 相同。
  • 是的,我知道函子和 monad 之间的关系,但我一直认为 bindfmap 具有更高的抽象级别(和功能)。看到fmap 在这里以更简洁的语法或多或少地完成了相同的工作,真是令人惊讶。
猜你喜欢
  • 2019-11-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多