如何理解Function as Functor
和Function as Applicative
?
首先,如何理解函数作为函子?
我们可以将函子视为一个空盒子,例如:
instance Functor Maybe where
fmap :: (a -> b) -> f a -> f b
fmap f (Just x) = Just (f x)
fmap f Nothing = Nothing
在那里,Maybe
type 可以看作是一个带有一个插槽的空框,它采用 type 来生成具体的 type Maybe a
。在fmap
函数中:
- 第一个参数是一个函数,从a映射到b;
- 第二个参数是槽填充的类型的值(具体类型),这个具体类型由类型构造函数生成,类型为fa(f is
Maybe
,所以fa is Maybe a
)。
当我们实现函数函子时,因为函子函子必须有两个参数才能构成一个类型a -> b
,如果我们想让函数函子只有一个槽,我们应该先填一个槽,所以函数函子的类型构造函数是 ((->) r ):
instance Functor ((->) r) where
fmap f g = (\x -> f (g x))
fmap
和 Functor 中的函数一样Maybe
,我们应该把第二个参数g看作是由f ( f等于)生成的一个具体类型的值(->) r
,所以fa可以(->) r a
看作是r -> a
。最后,不难理解,函数中的gx不能fmap
看成是,它只是一个函数应用,也r -> x
可以看成是。(r -> a) x
(x -> a)
最后,不难理解Applicative函数中的<*>函数(->) r
可以实现如下:
<*> :: f (a -> b) -> f a -> f b
<*> :: (r -> a -> b) -> (r -> a) -> (r -> b)
<&> :: (a -> b) -> (r -> a) -> (r -> b)
f <*> g = \r -> f r (g r)
因为gr将r映射到a,fra将r, a映射到b,所以整个 lambda 函数也可以看作r -> b
, f b
。例如:
((+) <*> (+3)) 5
结果是 5 + (5 + 3) = 13。
如何理解函数作为应用程序,(+) <$> (+3) <*> (*100) $ 5
= 508?
我们知道(+)
有类型:Num a, a -> a -> a
;
我们也知道(+3)
并且(*100)
有类型Num r, a, r -> a
:
(+) <$> (+3)
等于pure (+) <*> (+3)
, 其中:t pure (+)
等于Num _, a, _ -> a -> a -> a
换句话说,pure (+)
只是简单地接受一个_
参数并返回+
运算符,参数_
对最终返回值没有影响。pure (+)
还将函数的返回值映射(+3)
到函数。现在为
f <*> g = \r -> f r (g r)
我们可以应用运算符并获得:
pure (+) <*> (+3) =
\r -> f r (gr) =
\r -> + (gr) =
\r -> + (r + 3) =
\r x -> x + (r + 3)
它有类型r -> x -> a
。然后我们使用<*>的定义进行计算pure (+) <*> (+3) <*> (*100)
,得到:
pure (+) <*> (+3) <*> (*100) =
\r -> f r (gr) =
\r -> (r + 3) + (gr)
\r -> (r + 3) + (r * 100)
然后我们用参数 5 应用这个函数,我们得到:
(5 + 3) + (5 * 100) = 508
我们可以简单地将这种应用风格视为 first 计算 after 的值<$>
并与 operator before 相加<$>
。在上一个例子中,这个运算符是一个二元运算符 equals (+)
,我们可以将它替换为一个三元运算符(\x y z -> [x,y,z])
,所以下面的等式成立:
(\x y z -> [x,y,z]) <$> (+3) <*> (*2) <*> (/2) $ 5 = [8.0,10.0,2.5]