尝试使用Cont monad进行锻炼。语法问题

时间:2015-08-16 16:08:18

标签: haskell monads continuations

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

[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

1 个答案:

答案 0 :(得分:4)

首先,您无法按照发布的方式定义函数,原因与您无法实现上一个函数的原因相同,如下所示:

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)