几种 (applicative) functor/monad 的对比

学习 haskell 的过程中,functor/monad 的运算和应用是个坎。

光是从这几个的类簇(类型类)的定义来看,都太抽象了。 learn you a great haskell 是很好的入门书。对几种常见的 functor(monad) 都有介绍。但是在介绍它们的运算中符号使用得太灵活。同样的 f 有时是 functor, 有时是 function. 为了好好掌握,自己作了一下演算对比总结。

Laws

-- functor
fmap id == id

-- applicative functor
pure id <*> v = v
pure (.) <*> u <*> v <*> w = u <*> (v <*> w)
pure fn <*> pure x = pure (fn x)
u <*> pure y = pure ($ y) <*> u

-- Monad
return x >> f = f x
m >>= return = m
(m >>= f) >> g = m >>= (\x -> f x >>= g)

Definitions

class Functor f where
  fmap :: (a -> b) -> f a -> f b
class (Functor fr) => Applicative fr where
  fmap :: (a -> b) -> fr a -> fr b
  pure :: a -> fr a
  (<*>) :: fr (a -> b) -> fr a -> fr b
class Monad m where
  return :: a -> ma

  (>>=) :: ma -> (a -> m a) -> mb

  (>>) :: m a -> m b -> m b
  m x >> m y = m x >>= \_ -> m y

  fail :: String -> m a
  fail msg = error msg
liftA2 :: (Applicative fr) => (a -> b -> c) -> fr a -> fr b -> fr c
liftA2 fn x y = fn <$> x <*> y = fmap fn x <*> y
sequenceA :: (Applicative fr) => [fr a] -> fr [a]
sequenceA [] = pure []
sequenceA (x:xs) = (:) <$> x <*> sequenceA xs
sequenceA = foldr (liftA2 (:)) (pure [])
(<$>) :: (Functor fr) => (a -> b) -> fr a -> fr b
fn (<$>) x = fmap fn x
(<$>) = `fmap`
liftA2 :: (Applicative fr) => (a -> b -> c) -> fr a -> fr b -> fr c
liftA2 fn x y = fn <$> x <*> y = fmap fn x <*> y
sequenceA :: (Applicative fr) => [fr a] -> fr [a]
sequenceA [] = pure []
sequenceA (x:xs) = (:) <$> x <*> sequenceA xs
sequenceA = foldr (liftA2 (:)) (pure [])

Instances

Maybe

instance Applicative Maybe where
  -- functor
  fmap :: (a -> b) -> Maybe a -> Maybe b
  fmap f (Just x) = Just (f x)
  fmap Nothing = Nothing

  -- applicative functor
  pure :: a -> Just a
  pure = Just

  (<*>) :: Maybe(a -> b) -> Maybe a -> Maybe b
  Nothing <*> _ = Nothing
  (Just f) <*> Nothing = fmap f Nothing = Nothing
  (Just f) <*> (Just x) = fmap f (Just x) = Just (f x)
  (Just f) <*> something = fmap f something

  liftA2 :: (a -> b -> c) -> Maybe a -> Maybe b -> Maybe c
  liftA2 fn (Maybe x) (Maybe y)
    = fn <$> (Maybe x) <*> (Maybe y)
    = fmap fn (Maybe x) <*> (Maybe y)
    = Maybe (fn x) <*> Maybe y
    = Maybe (fn x y)

  sequenceA :: [Maybe a] -> Maybe [a]
  sequenceA :: (Maybe x):maybes = fmap (:) (Maybe x) <*> sequenceA maybes = Maybe (x:) <*> maybes
  sequenceA = foldr (liftA2 (:)) (Just [])

  -- monad
  return x = Just x

  (>>=) :: Maybe a -> (a -> Maybe b) -> Maybe b
  Nothing >>= f = Nothing
  Just x >>= f = f x

  foo :: Maybe String
  foo = Just 3 >>= \x -> Just "!" >>= \y -> Just (show x ++ y)
    = Just 3 >>= (\x -> Just "!" >>= (\y -> Just (show x ++ y)))
    = Just "!" >>= (\y -> Just (show 3 ++ y))
    = Just (show 3 ++ "!")
    = "3!"

  fail _ = Nothing

(Either e)

data Either a b = Left a | Right b

-- functor
instance Functor (Either a) where
  fmap :: (b -> c) -> Either a b -> Either a c
  fmap f (Right x) = Right (f x)
  fmap f (Left x) = Left x

-- monad
 instance (Error e) => Monad (Either e) where
   return :: a -> (Either e) a
   return x = Right x

   (>>=) :: (Either e a) -> (a -> Either e a) -> (Either e a)
   Right x >>= f = f x
   Left err >>= f = Left err
   fail msg = Left (strMsg msg)

List

instance Applicative [] where
  fmap :: (a -> b) -> [a] -> [b]
  fmap = map
  fmap [] = []
  fmap fn (x:xs) = (fn x):(fmap fn xs)

  pure :: a -> [a]
  pure x = [x]

  (<*>) :: [(a -> b)] -> [a] -> [b]
  fs <*> xs = [f x | f <- fs, x <- xs]

  liftA2 :: (a -> b -> c) -> [a] -> [b] -> [c]
  liftA2 fn xs ys
    = fn <$> xs <*> ys
    = fmap fn xs <*> ys
    = map fn xs <*> ys
    = [fn x y | x <- xs, y <- ys]

  sequenceA :: [[a]] -> [[a]]
  sequenceA (xs:xss) = map (:) x <*> sequenceA xss
  sequenceA = foldr (liftA2 (:)) ([[]])

instance Monad [] where
  return x = [x]

  (>>=) :: [a] -> (a -> [b]) -> [b]
  xs >>= f = concat (map f xs)

  foo :: [(Int, String)]
  foo = [1, 2] >>= \n -> ['a', 'b'] >>= \ch -> return (n, ch)
    = [1, 2] >>= (\n -> ['a', 'b'] >>= (\ch -> return (n, ch)))
    = concat [['a', 'b'] >>= (\ch -> return (1, ch)),
      ['a', 'b'] >>= (\ch -> return (2, ch))]
    = concat [concat [[(1, 'a')], [(1, 'b')]],
      concat [[(2, 'a')], [(2, 'b')]]]
    = concat [[(1, 'a'), (1, 'b')], [(2, 'a'), (2, 'b')]]
    = [(1, 'a'), (1, 'b'), (2, 'a'), (2,'b')]

  fail _ = []

IO

instance Applicative IO where
  fmap :: (a -> b) -> IO a -> IO b
  fmap f action = do
    result <- action
    return (f action)

  pure :: a -> IO a
  pure = return
  pure x = return x

  (<*>) :: IO(a -> b) -> IO a -> IO b
  a <*> b = do
    f <- a
    x <- b
    return (f x)

  liftA2 :: (a -> b -> c) -> IO a -> IO b -> IO c
  liftA2 fn (IO x) (IO y)
    = fn <$> (IO x) (IO y)
    = fmap fn (IO x) <*> (IO y)
    = IO (fn x) <*> (IO y)
    = IO (fn x y)

  sequenceA :: [IO a] -> IO [a]
  sequenceA = foldr (liftA2 (:)) (IO [])

function

instance Applicative ((->) r) where
  fmap :: (a -> b) -> (r -> a) -> (r -> b)
  fmap f g = (\x -> f(g(x)))
  fmap = (.)

  pure :: a -> (r -> a)
  pure x = (\_ -> x)

  (<*>) :: (r -> (a -> b)) -> (r -> a) -> (r -> b)
  f <*> g = \x -> f x (g x)

instance Monad ((->) r) where
  return :: r -> (r -> a)
  return x = \_ -> x

  (>>=) :: (r -> a) -> (a -> (r -> b)) -> r -> b
  h >>= fn = \w -> fn (h w) w

ZipList

instance Applicative ZipList where
  fmap :: (a -> b) -> ZipList a -> ZipList b

  pure :: a -> ZipList [a]
  pure x = ZipList (repeat x)

  (<*>) :: ZipList[a -> b] -> ZipList [a] -> ZipList [b]
  ZipList fs <*> ZipList xs = ZipList (zipWith (\f x -> f x) fs xs)

  liftA2 :: (a -> b -> c) -> ZipList a -> ZipList b -> ZipList c
    = fn <$> ZipList xs <*> ZipList ys
    = fmap fn ZipList xs <*> ZipList ys
    = ZipList (map fn xs) <*> ZipList ys
    = ZipList (zipWith (\f x -> f x) (map fn xs) ys)

  sequenceA :: [ZipList a] -> ZipList [a]
  sequenceA ((ZipList xs):zls) = ZipList (map (:) xs) <*> sequenceA zls
  sequenceA = foldr (liftA2 (:)) (ZipLits [])
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,723评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,485评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,998评论 0 344
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,323评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,355评论 5 374
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,079评论 1 285
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,389评论 3 400
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,019评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,519评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,971评论 2 325
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,100评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,738评论 4 324
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,293评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,289评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,517评论 1 262
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,547评论 2 354
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,834评论 2 345

推荐阅读更多精彩内容