Haskell: (-」) r Functor Applicative Monad 案例选讲

Haskell: (->) r Functor Applicative Monad 案例选讲

(->) r 的 Functor Applicative Monad 方法实现

类型构造器(->) rFunctor Applicative Monad的实例,相关定义如下:

instance Functor ((->) r) where
    fmap = (.)
    (<$>) = fmap

instance Applicative ((->) r) where
    pure x _ = x
    (<*>) f g = \x -> f x (g x)

instance Monad ((->) r) where  
    return x _ = x  
    h >>= f = \x -> f (h x) x  

(因为在文档里面不好找,所以整理出来)

一些案例

在ghci中进行下列尝试时,请先:m + Prelude Control.Monad Control.Applicative

liftA系列

这些函数的定义如下:

-- | Lift a function to actions.
-- This function may be used as a value for `fmap` in a `Functor` instance.
liftA :: Applicative f => (a -> b) -> f a -> f b
liftA f a = pure f <*> a

-- | Lift a binary function to actions.
liftA2 :: Applicative f => (a -> b -> c) -> f a -> f b -> f c
liftA2 f a b = f <$> a <*> b

-- | Lift a ternary function to actions.
liftA3 :: Applicative f => (a -> b -> c -> d) -> f a -> f b -> f c -> f d
liftA3 f a b c = f <$> a <*> b <*> c

应用:

1.Applicative里面的<*, *>算符就是借助liftA2定义的。

class Functor f => Applicative f where
    -- | Lift a value.
    pure :: a -> f a

    -- | Sequential application.
    (<*>) :: f (a -> b) -> f a -> f b

    -- | Sequence actions, discarding the value of the first argument.
    (*>) :: f a -> f b -> f b
    (*>) = liftA2 (const id)

    -- | Sequence actions, discarding the value of the second argument.
    (<*) :: f a -> f b -> f a
    (<*) = liftA2 const

{-
in which
const    x y = x (returns the 1st parameter)
const id x y = y (returns the 2nd parameter)
-}

2.liftA系列的函数,在(->) r类型的用法是,对同一个自变量,先用各个函数转换成应有的类型(称为lift),再feed进最开头的多元函数。

首先举一个算数的例子:

   liftA2 (+) <$> f <*> g x
 = (\x1 x2 -> f x1 + x2) <*> g x
 = (\x3 -> (\x1 x2 -> f x1 + x2) x3 (g x3)) x
 = (\x1 x2 -> f x1 + x2) x (g x)
 = f x + g x

其中(+)可以换为任何一个二元运算。

应用举例:liftA2 (+) (+2) (*10) 3 = (+2) 3 + (*10) 3 = 5 + 30 = 35

再举一个更一般的例子:let f = \c x -> take x (repeat c) in liftA3 (\x y z -> x ++ y ++ z) (f 'a') (f 'b') (f 'c') 2 = "aabbcc"

也就是说,liftA3 f g1 g2 g3 x = f (g1 x) (g2 x) (g3 x), liftA2 f g1 g2 x = f (g1 x) (g2 x)

类似的,liftA f g x = f (g x).liftA的定义形式和liftA2, liftA3不同,但效果一样。这里面肯定揭露了一些本质性的东西,但暂时还没想明白。可能本质上是利用了pure函数的某个性质。(欢迎指教!)

liftM

-- | Promote a function to a monad.
liftM   :: (Monad m) => (a1 -> r) -> m a1 -> m r
liftM f m1              = do { x1 <- m1; return (f x1) }

-- | Promote a function to a monad, scanning the monadic arguments from
-- left to right.  For example,
--
-- >    liftM2 (+) [0,1] [0,2] = [0,2,1,3]
-- >    liftM2 (+) (Just 1) Nothing = Nothing
-- >    liftM2 (+) (+1) (*2) x = (+1) x + (*2) x
--
liftM2  :: (Monad m) => (a1 -> a2 -> r) -> m a1 -> m a2 -> m r
liftM2 f m1 m2          = do { x1 <- m1; x2 <- m2; return (f x1 x2) }

-- | Promote a function to a monad, scanning the monadic arguments from
-- left to right (cf. 'liftM2').
liftM3  :: (Monad m) => (a1 -> a2 -> a3 -> r) -> m a1 -> m a2 -> m a3 -> m r
liftM3 f m1 m2 m3       = do { x1 <- m1; x2 <- m2; x3 <- m3; return (f x1 x2 x3) }

-- liftM4  :: (Monad m) => (a1 -> a2 -> a3 -> a4 -> r) -> m a1 -> m a2 -> m a3 -> m a4 -> m r
-- liftM5  :: (Monad m) => (a1 -> a2 -> a3 -> a4 -> a5 -> r) -> m a1 -> m a2 -> m a3 -> m a4 -> m a5 -> m r

liftA基本一码事。

另外提到ap函数:

liftM2 :: Monad m => (a1 -> a2 -> r) -> m a1 -> m a2 -> m r

ap :: Monad m => m (a -> b) -> m a -> m b
ap = liftM2 id -- a1 = a -> b, a2 = a, r = b

在实现了Monad实例的类型中,Haskell标准要求<*>ap是等价的.自己推一下ap (+) (*2) 10就知道为什么了,也可以自己证明一下。

>>=相关

心情好的时候会把文档里面和>>=相关的函数捋一遍,然后就会发现一些原本认为很高阶的函数,在monad中都是>>=的special case,都可以用return>>=和一些简单函数重新构建,从而发现monad的强大。

烂尾了 心情好的时候再补

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章