classFoldable t where fold :: Monoid m => t m -> m foldMap :: Monoid m => (a -> m) -> t a -> m foldMap' :: Monoid m => (a -> m) -> t a -> m foldr :: (a -> b -> b) -> b -> t a -> b foldr' :: (a -> b -> b) -> b -> t a -> b foldl :: (b -> a -> b) -> b -> t a -> b foldl' :: (b -> a -> b) -> b -> t a -> b foldr1 :: (a -> a -> a) -> t a -> a foldl1 :: (a -> a -> a) -> t a -> a toList :: t a -> [a] null :: t a -> Bool length :: t a -> Int elem :: Eq a => a -> t a -> Bool maximum :: Ord a => t a -> a minimum :: Ord a => t a -> a sum :: Num a => t a -> a product :: Num a => t a -> a {-# MINIMAL foldMap | foldr #-}
dataTree a = Empty | Leaf a | Node (Treea) a (Treea) instanceFoldableTreewhere foldMap :: Monoid m => (a -> m) -> Tree a -> m foldMap f Empty = mempty foldMap f (Leaf x) = f x foldMap f (Node l k r) = foldMap f l `mappend` f k `mappend` foldMap f r
常用函数
asum :: (Alternative f, Foldable t) => t (f a) -> f a,用<|>逐个连接所有元素
sequenceA_ :: (Applicative f, Foldable t) => t (f a) -> f (),由于丢弃结果,所以Foldable t就可以满足;因此不同于sequenceA需要Traversable
traverse_ :: (Applicative f, Foldable t) => (a -> f b) -> t a -> f ()
for_ :: (Applicative f, Foldable t) => t a -> (a -> f b) -> f ()
class (Functort, Foldablet) => Traversable t where traverse :: Applicative f => (a -> f b) -> t a -> f (t b) sequenceA :: Applicative f => t (f a) -> f (t a) mapM :: Monad m => (a -> m b) -> t a -> m (t b) sequence :: Monad m => t (m a) -> m (t a) {-# MINIMAL traverse | sequenceA #-}
instanceTraversableMaybewhere traverse _ Nothing = pure Nothing traverse f (Just x) = Just <$> f x instanceTraversable [] where {-# INLINE traverse #-} traverse f = foldr cons_f (pure []) where cons_f x ys = liftA2 (:) (f x) ys instanceTraversable (Eithera) where traverse _ (Left x) = pure (Left x) traverse f (Right y) = Right <$> f y instanceTraversable ((,) a) where traverse f (x, y) = (,) x <$> f y
...
上面的Tree也可以成为Traversable的实例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
instanceFunctorTreewhere fmap :: (a -> b) -> Tree a -> Tree b fmap g Empty = Empty fmap g (Leaf x) = Leaf $ g x fmap g (Node l x r) = Node (fmap g l) (g x) (fmap g r) instanceTraversableTreewhere traverse :: Applicative f => (a -> f b) -> Tree a -> f (Tree b) traverse g Empty = pure Empty traverse g (Leaf x) = Leaf <$> g x traverse g (Node l x r) = Node <$> traverse g l <*> g x <*> traverse g r
Traversable Laws
Traversable也有两条定律:
traverse Identity = Identity
traverse (Compose . fmap g . f) = Compose . fmap (traverse g) . traverse f
classBifunctor p where bimap :: (a -> b) -> (c -> d) -> p a c -> p b d first :: (a -> b) -> p a c -> p b c second :: (b -> c) -> p a b -> p a c {-# MINIMAL bimap | first, second #-}
classCategory cat where id :: cat a a (.) :: cat b c -> cat a b -> cat a c
它的实例有(->)和Kleisli m:
1 2 3
instanceCategory (->) where id = GHC.Base.id (.) = (GHC.Base..)
Kleisli是一个范畴,用来表示函数a -> m b,Haskell中,它在Control.Arrow模块中定义:
1 2 3 4 5 6 7 8
newtypeKleisli m a b = Kleisli { runKleisli :: a -> mb } instanceMonad m => Category (Kleislim) where id :: Kleisli m a a id = Kleisli return
(.) :: Kleisli m b c -> Kleisli m a b -> Kleisli m a c Kleisli g . Kleisli h = Kleisli (h >=> g)
Category要满足的定律只有id是(.)操作的单位元,以及(.)操作是可结合的
同时Category还提供了两个函数<<<和>>>:
1 2 3 4 5
(<<<) :: Category cat => cat b c -> cat a b -> cat a c (<<<) = (.)
(>>>) :: Category cat => cat a b -> cat b c -> cat a c f >>> g = g . f
Arrow
Arrow将函数进一步抽象化,它定义在Control.Arrow模块中:
1 2 3 4 5 6 7
classCategory a => Arrow a where arr :: (b -> c) -> a b c first :: a b c -> a (b, d) (c, d) second :: a b c -> a (d, b) (d, c) (***) :: a b c -> a b' c' -> a (b, b') (c, c') (&&&) :: a b c -> a b c' -> a b (c, c') {-# MINIMAL arr, (first | (***)) #-}
&&&函数是Arrow之间的fanout composition,对于函数: (g &&& h) x = (g x, h x)
它的实例也有(->)和Kleisli:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
instanceArrow (->) where arr :: (b -> c) -> (b -> c) arr g = g
first :: (b -> c) -> ((b,d) -> (c,d)) first g (x,y) = (g x, y) instanceMonad m => Arrow (Kleislim) where arr :: (b -> c) -> Kleisli m b c arr f = Kleisli (return . f)
first :: Kleisli m b c -> Kleisli m (b,d) (c,d) first (Kleisli f) = Kleisli (\ ~(b,d) -> do c <- f b return (c,d) )
常用函数:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
returnA :: Arrow a => a b b returnA = arr id
(^>>) :: Arrow a => (b -> c) -> a c d -> a b d f ^>> a = arr f >>> a
(>>^) :: Arrow a => a b c -> (c -> d) -> a b d a >>^ f = a >>> arr f
(<<^) :: Arrow a => a c d -> (b -> c) -> a b d a <<^ f = a <<< arr f
(^<<) :: Arrow a => (c -> d) -> a b c -> a b d f ^<< a = arr f <<< a
Arrow notation
类似do-notation,Arrow也提供了一套方便的语句:
1 2 3 4
proc x -> do y <- action1 -< ... z <- action2 -< ... returnA -< ...
classArrow a => ArrowChoice a where left :: a b c -> a (Either b d) (Either c d) left = (+++ id)
right :: a b c -> a (Either d b) (Either d c) right = (id +++)
(+++) :: a b c -> a b' c' -> a (Either b b') (Either c c') f +++ g = left f >>> arr mirror >>> left g >>> arr mirror where mirror :: Either x y -> Either y x mirror (Left x) = Right x mirror (Right y) = Left y
(|||) :: a b d -> a c d -> a (Either b c) d f ||| g = f +++ g >>> arr untag where untag (Left x) = x untag (Right y) = y instanceArrowChoice (->) where left f = f +++ id right f = id +++ f f +++ g = (Left . f) ||| (Right . g) (|||) = either instanceMonad m => ArrowChoice (Kleislim) where left f = f +++ arr id right f = arr id +++ f f +++ g = (f >>> arr Left) ||| (g >>> arr Right) Kleisli f ||| Kleisli g = Kleisli (either f g)
ArrowZero & ArrowPlus
1 2 3 4 5 6 7 8 9 10 11
classArrow a => ArrowZero a where zeroArrow :: a b c classArrowZero a => ArrowPlus a where (<+>) :: a b c -> a b c -> a b c instanceMonadPlus m => ArrowZero (Kleislim) where zeroArrow = Kleisli (\_ -> mzero) instanceMonadPlus m => ArrowPlus (Kleislim) where Kleisli f <+> Kleisli g = Kleisli (\x -> f x `mplus` g x)