2012-01-04 51 views
10

它在Validations in Haskell中声称使用Writer可保证右关联级联。但是,这个例子似乎表明了其他情况。什么是正确的答案?Writer Monad保证正确的关联级联吗?

{-# LANGUAGE OverloadedStrings #-} 

import Control.Monad.Writer 
import Data.String 

data TM = TMempty 
     | TMappend TM TM 
     | TMfromString String 

instance IsString TM where 
    fromString = TMfromString 

instance Monoid TM where 
    mempty = TMempty 
    mappend = TMappend 

instance Show TM where 
    showsPrec d TMempty = showString "\"\"" 
    showsPrec d (TMfromString s) = showString $ show s 
    showsPrec d (TMappend a b) = showParen (d > 0) $ 
    showsPrec 1 a . 
    showString " ++ " . 
    showsPrec 0 b 

theWriter :: Writer TM() 
theWriter = do 
    tell "Hello" 
    replicateM_ 2 $ tell "World" 
    tell "!" 

main = print $ execWriter theWriter 

产地:

"Hello" ++ ("World" ++ "World" ++ "") ++ "!" 
+0

对于使用和实现'showsPrec'的简单示例+1。 – 2012-01-04 19:10:26

+0

有趣的是,如果用'replicateM'替换'replicateM_',则输出变成''Hello“++(”World“++(”World“++”“++”“)++”“)++” !'''' – pat 2012-01-04 20:08:55

+3

'sequence'和'sequence_':'sequence = foldr(liftM2(:))(return [])'''但是'sequence_ = foldr(>>)(return())'之间的区别。前者会产生更多的绑定,因为它会对结果进行处理。 – ehird 2012-01-04 20:11:30

回答

7

是的,这确实是不真实的。从source code

m >>= k = WriterT $ do 
    ~(a, w) <- runWriterT m 
    ~(b, w') <- runWriterT (k a) 
    return (b, w `mappend` w') 

... 

-- | @'tell' [email protected] is an action that produces the output @[email protected] 
tell :: (Monoid w, Monad m) => w -> WriterT w m() 
tell w = WriterT $ return ((), w) 

所以mappend S中的链将镜像的(>>=) S上的链条。

1

Writer [a]不保证右联合级联,但是您可以通过Writer (Endo [a])获得有保证的右联合级联。