Monoid 也应用在 Foldable 类型类的 foldMap 函数中。foldMap 的型别声明为 (Foldable t, Monoid m) => (a -> m) -> t a -> m。可以为自定义类型实作 Foldable 类型类,即可通过 foldMap 对自定义类型的元素做 map over、折叠等操作。注意 foldMap 和 fmap 的区别在于 foldMap 不会将函数返回值再次包装到原类型类中,而是包装到 Monoid 中。举个例子,对于自定义类型 data Tree a = Node a (Tree a) (Tree a) | Empty,要想确定树中有无小于 0 的元素,只需 getAny $ foldMap (\x -> Any $ x < 0) tree,这里 foldMap 把树中每个元素映射到 Any Monoid 中。
Monad
Monad (Control.Monad)类型类定义如下:
1 2 3 4 5 6 7
classApplicative m => Monad m where (>>=) :: m a -> (a -> m b) -> m b (>>) :: m a -> m b -> m b x >> y = x >>= \_ -> y return :: a -> m a fail :: String -> m a fail msg = error msg
newtypeWriter w a = Writer{ runWriter :: (a, w) } instance(Monoidw) => Monad(Writerw)where return x = Writer (x, mempty) (Writer (x, v)) >>= f = letWriter (y, v') = f x inWriter (y, v `mappend` v')
可用 tell 向 Writer 加入 log。
((->) r)
函数也是 Monad,其实例为:
1 2 3
instanceMonad((->) r) where return = const g >>= f = \v -> f (g v) v
Reader
Reader (对函数 Monad 的一种包装):
1 2 3 4 5
newtypeReader s a = Reader{ runReader :: s -> a } instanceMonad(Readers)where return x = Reader (const x) m >>= k = Reader $ \r -> runReader (k (runReader m r)) r
State
State (Control.Monad.State)常用来表示状态迁移,代表了改变状态的操作:
1 2 3 4 5 6 7
newtypeState s a = State{runState :: s -> (a, s)} instanceMonad(States)where return x = State $ \s -> (x, s) (State h) >>= f = State $ \s -> let (a, newState) = h s (State g) = f a in g newState