问题导出
move i = do
x <- left i
tell "Go"
y <- left x
return y
其中
left i = writer ( x -1,"move left\t')
:t tell "G0" :: MonadWriter [Char] m => m ()
问题
tell "Go"的上下文到底在哪里
我们一步步的解开
move :: Int -> Writer String Int
move i = do
x <- left' i
_ <- tell "GO\t"
return x
我们把do展开
move i = let
ok p = do
tell "go"
return p
ok _ = fail ".."
in writer ((i-1),"Move Left\t") >>= ok
展开tell
move' i = let
ok p = do
writer ((),"Go\t")
return p
ok _ = fail ".."
in writer ((i-1),"Move Left\t") >>= ok
将let解构转换为where解构,暂时消除掉i
move i = writer ((i-1),"Move Left\t") >>= ok where
ok p = do
writer ((),"Go\t")
return p
消除掉第二个do
move i = writer ((i-1),"Move Left\t") >>= ok where
ok p = writer ((),"Go\t") >> return p
增加辅助函数,做最终转换
instance (Monoid w) => Monad (Writer w) where
return x = Writer (x,mempty)
(Writer (x,v)) >>= f = let (Writer ( y,v')) = fx
in Writer (y, v `mappend` v')
temp ::Int -> Writer String Int
temp i = writer ((),"GO\t") >> return (i-1)
move i = case runWriter(temp i) of
(y,v') -> writer (y, "Move Left\t" `mappend` v')
_ -> writer(0,mempty)
对于temp的模拟,可以参看monad这里的对于>>的实现,确实是使用了>>=。这样既满足了需要串行运算上下文,又能保证丢弃了上文的M a的a,但是仍然可以把M传递给下文。而恰好,Writer的声明形式是Writer String a,这样可以把a丢弃掉,而把String传递给下文,达到了tell要求的仅保留String内容,而忽略a的内容.
结论:
可以看出,上下文首先是因为做了内部的do运算,得到的关键的Writer((),"Go"),
之后把(i-1) 附属到了tell的结果上,然后再做外部运算,结束掉x <- left i。
本文详细解析了move函数中上下文的处理过程,包括内部do运算的关键内容、tellGo操作的上下文作用及最终转换为Writer类型的过程。通过逐步分解,揭示了move函数如何在上下文中进行信息传递。
687

被折叠的 条评论
为什么被折叠?



