2012-01-04 47 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])獲得有保證的右聯合級聯。