Haskell语言学习笔记(10)Writer Monad
来源:互联网 发布:台湾版淘宝官网 编辑:程序博客网 时间:2024/06/05 15:10
Writer 是 Monad
旧的定义newtype Writer w a = Writer { runWriter :: (a, w) }instance (Monoid w) => Monad (Writer w) where return x = Writer (x, mempty) (Writer (x,v)) >>= f = let (Writer (y, v')) = f x in Writer (y, v `mappend` v')这里旧的定义是指API更改之前的定义,也就是Learn You a Haskell for Great Good!(中文版Haskell趣学指南)这本书中的定义。
- newtype Writer w a = Writer { runWriter :: (a, w) }
这里 Writer 类型是个 newtype,也就是对现有类型的封装。Writer 类型有两个类型参数:表示状态的类型参数 w 以及表示结果的类型参数 a。
这里 Writer 类型封装的是一对值:(a,w),包括结果值 a 和状态值 w。通过 runWriter 字段可以从 Writer 类型中取出这对值。 - instance (Monoid w) => Monad (Writer w) where
(Writer w) 类型是 Monad 类型类的一个实例,前提是 w 类型是 Monoid 类型类的一个实例。
对比 Monad 类型类的定义,可知 return 函数的类型签名为:
return :: x -> Writer w x
而 bind 函数的类型签名为:
(>>=) :: Writer w a -> (a -> Writer w a) -> Writer w a - return x = Writer (x, mempty)
return 函数将结果值设为 x, 状态值设为单位元。 - (Writer (x,v)) >>= f = let (Writer (y, v')) = f x in Writer (y, v `mappend` v')
对比函数签名,可知 f 的类型为 (a -> Writer w a)。
bind组合函数首先计算 f x,即是用原来的结果值 x 来调用 f,其结果为新的结果值 y 以及新的状态值 v'。
然后将结果值设为新的结果值 y,状态值则设为原来的状态值 v 与新的状态值 v' 联结后的值。
newtype WriterT w m a = WriterT { runWriterT :: m (a, w) }instance (Monoid w, Monad m) => Monad (WriterT w m) where return a = WriterT $ return (a, mempty) m >>= k = WriterT $ do ~(a, w) <- runWriterT m ~(b, w') <- runWriterT (k a) return (b, w `mappend` w')type Writer w = WriterT w Identity根据新的定义,Writer 类型只是 WriterT 类型的一个特例。
Writer Monad 函数
- writer (a,w):将一对结果值和状态值封装进Writer Monad。
- tell w:将状态值设为 w,结果值设为空。
- listen (a,w):将结果值设为 (a,w),状态值设为 w。
- pass ((a,f),w):将结果值设为 a,状态值设为 f w。
gcd
import Control.Monad.Trans.Writergcd' :: Int -> Int -> Writer [String] Intgcd' a b | b == 0 = do tell ["Finished with " ++ show a] return a | otherwise = do tell [show a ++ " mod " ++ show b ++ " = " ++ show (a `mod` b)] gcd' b (a `mod` b)main = mapM_ putStrLn . snd . runWriter $ gcd' 8 3{-8 mod 3 = 23 mod 2 = 12 mod 1 = 0Finished with 1=}
gcd
import Control.Monad.Trans.Writernewtype DiffList a = DiffList { getDiffList :: [a] -> [a] }toDiffList :: [a] -> DiffList atoDiffList xs = DiffList (xs++)fromDiffList :: DiffList a -> [a]fromDiffList (DiffList f) = f []instance Monoid (DiffList a) where mempty = DiffList (\xs -> [] ++ xs) (DiffList f) `mappend` (DiffList g) = DiffList (\xs -> f (g xs))gcd'' :: Int -> Int -> Writer (DiffList String) Intgcd'' a b | b == 0 = do tell (toDiffList ["Finished with " ++ show a]) return a | otherwise = do result <- gcd'' b (a `mod` b) tell (toDiffList [show a ++ " mod " ++ show b ++ " = " ++ show (a `mod` b)]) return resultmain = mapM_ putStrLn . fromDiffList . snd . runWriter $ gcd'' 8 3{-Finished with 12 mod 1 = 03 mod 2 = 18 mod 3 = 2=}
0 0
- Haskell语言学习笔记(10)Writer Monad
- Haskell语言学习笔记(6)Monad
- Haskell语言学习笔记(9)State Monad
- Haskell语言学习笔记(24)MonadWriter, Writer, WriterT
- Haskell语言学习笔记(1)
- Haskell语言学习笔记(2)
- Haskell语言学习笔记(4)Functor
- Haskell语言学习笔记(5)Applicative
- Haskell语言学习笔记(8)Monoid
- Haskell语言学习笔记(14)Foldable
- Haskell语言学习笔记(16)Alternative
- Haskell语言学习笔记(17)MonadPlus
- Haskell语言学习笔记(18)Traversable
- Haskell语言学习笔记(21)Array
- Haskell语言学习笔记(22)MaybeT
- Haskell语言学习笔记(29)CPS
- Haskell语言学习笔记(31)ListT
- Haskell语言学习笔记(35)Contravariant
- 洛谷 1583——魔法照片(排序Ex)
- 关于Oracle数据库的整理
- [bzoj2655] calc
- pat a1008(暂缺)
- 基于TFT的ZLG_GUI和3D显示的移植
- Haskell语言学习笔记(10)Writer Monad
- 机器学习之深入理解SVM
- 简单的播放内存卡中音乐的播放器
- 谷哥的小弟学后台(12)——Servlet(4)
- 【说一千道一万】Java内存
- 树莓派+python+打印串口数据
- 不是人人都懂的学习要点
- linux上anaconda的卸载
- Python 序列