我正在学习do expression
和Monad
使用了解你是一个非常好的HASKELL 。使用gcd
函数的tell
实现让我感到困惑。
gcd :: Int -> Int -> Writer [String] Int
gcd a b
| b == 0 = tell ["Finished with " ++ show a ] >>= (\_ -> return a)
| otherwise = tell [show a ++ " mod " ++ show b ++ " = " ++ show (a `mod` b)] >>= (\_ -> gcd b (a `mod` b))
gcdResult = gcd 8 3
-- result: WriterT (Identity (1,["8 mod 3 = 2","3 mod 2 = 1","2 mod 1 = 0","Finished with 1"]))
但我对tell
函数感到困惑。使用>>= (\_ -> ...)
或>>
时,之前的结果将被忽略,那么为什么tell
的结果可以传递给最终结果?根据我的想法,tell
结果可能会被忽略,最终结果将是WriterT (Identity (1,[]))
。
答案 0 :(得分:12)
您将结果与上下文混淆。您是正确的,在应用>>
或>>= \_ ->
时,会忽略左侧的结果。但是,如果忽略整个价值,那将是完全没有意义的; monadic环境可以向前传递。
a >> b
这意味着“从a
获取上下文并将其与b
的上下文相结合,保持结果值为b
”。在Writer
的情况下,monadic上下文是传递了一些只写数据。
tell :: Monoid w => w -> Writer w ()
这是tell
的(略微简化)类型。它需要一个值来编写并返回一个Writer
实例,其结果值无关紧要(()
),但其上下文是包含w
参数的只写值。当您应用>>
时,结果值将被忽略(这是无关紧要的,因为tell
在结果中没有返回任何值),但保留了上下文。