2016-10-02 79 views
0

我的代碼如下所示:如何使用Monad.Writer進行跟蹤?

我想在tokenize函數中使用tell來寫入相同的Writer Monad。這可能嗎 ?

tokenize :: T.Text -> T.Text -> [Token] 
tokenize t token 
    | T.null t = addToken token [] 
    | h == ' ' = addToken token (tokenize r "") 
    | h == '"' = let (t', r') = consumeString r 
       in addToken t' (tokenize r' "") 
    | otherwise = tokenize r (T.snoc token h) 
    where h = T.head t 
     r = T.tail t 

parse :: [T.Text] -> W.Writer String [Token] 
parse lines = do 
    let x = concatMap (\l -> tokenize l "") lines 
    W.tell "hello" 
    return x 

main :: IO() 
main = do 
    content <- readContent 
    let lines = toTextList content 
    let (res, log) = W.runWriter $ parse lines 
    forM_ res $ \x -> 
     print x 
    print log 
+0

辦法之一使用'x <- concat <$> mapM(\ l - > tokenize l「」)行並且以單子方式重寫'tokenize'。我對此並不滿意,因爲我們失去了'concatMap'的流媒體性能。我想知道是否可以使monadic版本以某種方式保存流媒體,知道我們在這裏使用作家monad ... – chi

+0

@chi我沒有想到性能影響。將'concatMapM'定義爲摺疊有幫助嗎? – user2297560

+0

@ user2297560在處理通用monad時,我不認爲有效的'concatMapM'可以存在。在作家的具體情況下......我不知道。 – chi

回答

1

你只需要的tokenize結果提升到了Writer

tokenize :: T.Text -> T.Text -> W.Writer [Token] 
tokenize t token 
    | T.null t = return $ addToken token [] 
    | h == ' ' = return $ addToken token (tokenize r "") 
    | h == '"' = let (t', r') = consumeString r 
       in return $ addToken t' (tokenize r' "") 
    | otherwise = return $ tokenize r (T.snoc token h) 
    where h = T.head t 
     r = T.tail t 

然後parse必須改變從tokenize處理單子結果:

parse :: [T.Text] -> W.Writer String [Token] 
parse lines = do 
    x <- concat <$> mapM (\l -> tokenize l "") lines 
    W.tell "hello" 
    return x