经过一些研究([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
答案 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)