Haskell的WriterMonad解构

本文详细解析了move函数中上下文的处理过程,包括内部do运算的关键内容、tellGo操作的上下文作用及最终转换为Writer类型的过程。通过逐步分解,揭示了move函数如何在上下文中进行信息传递。

问题导出

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值