为什么 fmap f xs = pure f <*> xs?
Why fmap f xs = pure f <*> xs?
class Functor f => Applicative f where
pure :: a -> f a
(<*>) :: f (a -> b) -> f a -> f b
"pure" plays two roles:
* The degenerate case when you have a
0-ary function, kind of.
* fmap f xs = pure f <*> xs
我不明白为什么
fmap f xs = pure f <*> xs
我的意思是 pure
应该取任何 a
和 return f a
。但是 pure f
是做什么的呢?甚至 pure (f <*> xs)
对我来说也有意义。
But what does pure f
do?
给定 f :: a -> b
,我们得到 pure f :: f (a -> b)
最后一个 f
是任何应用函子。这将创建一个正确类型的值作为第一个参数传递给
(<*>) :: f (a -> b) -> f a -> f b
I mean pure
should take any a
and return f a
完全正确 - 在这种情况下,您提到的 a
是我上面提到的函数类型 a -> b
。
也许一个具体的例子可以说明问题。拿名单applicative。 <*>
将其左侧操作数的 each 函数应用于其右侧的 each 值:
fs <*> xs = [f x | f <- fs, x <- xs]
并且pure
将值包装在单例列表中:
pure (+ 1) = [(+ 1)]
所以 pure f <*> xs
= fmap f xs
,因为 <*>
应用每个函数——其中恰好只有一个 ——到每个值,而 fmap
对每个值应用一个函数:
pure (+ 1) <*> [1, 2, 3]
=
[(+ 1)] <*> [1, 2, 3]
=
[f x | f <- [(+ 1)], x <- [1, 2, 3]]
=
[(+ 1) x | x <- 1, 2, 3]
=
[x + 1 | x <- 1, 2, 3]
=
[2, 3, 4]
fmap (+ 1) [1, 2, 3]
=
[(+ 1) x | x <- [1, 2, 3]]
=
[x + 1 | x <- [1, 2, 3]]
=
[2, 3, 4]
这也是 <$>
和 <*>
运算符协同工作以对多个操作的结果应用多参数函数的方式,例如:
(*) <$> [1..5] <*> [1..5]
=
((*) <$> [1..5]) <*> [1..5]
=
[(1 *), (2 *), (3 *), (4 *), (5 *)] <*> [1..5]
=
[ (1 *) 1, (2 *) 1, (3 *) 1, (4 *) 1, (5 *) 1
, (1 *) 2, (2 *) 2, (3 *) 2, (4 *) 2, (5 *) 2
, (1 *) 3, (2 *) 3, (3 *) 3, (4 *) 3, (5 *) 3
, (1 *) 4, (2 *) 4, (3 *) 4, (4 *) 4, (5 *) 4
, (1 *) 5, (2 *) 5, (3 *) 5, (4 *) 5, (5 *) 5
]
=
[ 1, 2, 3, 4, 5
, 2, 4, 6, 8, 10
, 3, 6, 9, 12, 15
, 4, 8, 12, 16, 20
, 5, 10, 15, 20, 25
]
这也可以写成pure (*) <*> [1..5] <*> [1..5]
。
<$>
构建一个动作(在本例中为列表)返回(包含)部分应用的函数,<*>
获取这些函数并将它们应用于参数。 (如果函数接受两个以上的参数,那么这也可能导致部分应用函数,可以通过 <*>
的另一个应用程序将其应用于更多参数。)
同样的法则适用于其他“类似容器”的应用程序,例如 Maybe
或 Either e
(对于某些 e
),以及“类似动作”的应用程序,例如作为 IO
、Cont r
或 Async
.
class Functor f => Applicative f where
pure :: a -> f a
(<*>) :: f (a -> b) -> f a -> f b
"pure" plays two roles:
* The degenerate case when you have a 0-ary function, kind of.
* fmap f xs = pure f <*> xs
我不明白为什么
fmap f xs = pure f <*> xs
我的意思是 pure
应该取任何 a
和 return f a
。但是 pure f
是做什么的呢?甚至 pure (f <*> xs)
对我来说也有意义。
But what does
pure f
do?
给定 f :: a -> b
,我们得到 pure f :: f (a -> b)
最后一个 f
是任何应用函子。这将创建一个正确类型的值作为第一个参数传递给
(<*>) :: f (a -> b) -> f a -> f b
I mean
pure
should take anya
and returnf a
完全正确 - 在这种情况下,您提到的 a
是我上面提到的函数类型 a -> b
。
也许一个具体的例子可以说明问题。拿名单applicative。 <*>
将其左侧操作数的 each 函数应用于其右侧的 each 值:
fs <*> xs = [f x | f <- fs, x <- xs]
并且pure
将值包装在单例列表中:
pure (+ 1) = [(+ 1)]
所以 pure f <*> xs
= fmap f xs
,因为 <*>
应用每个函数——其中恰好只有一个 ——到每个值,而 fmap
对每个值应用一个函数:
pure (+ 1) <*> [1, 2, 3]
=
[(+ 1)] <*> [1, 2, 3]
=
[f x | f <- [(+ 1)], x <- [1, 2, 3]]
=
[(+ 1) x | x <- 1, 2, 3]
=
[x + 1 | x <- 1, 2, 3]
=
[2, 3, 4]
fmap (+ 1) [1, 2, 3]
=
[(+ 1) x | x <- [1, 2, 3]]
=
[x + 1 | x <- [1, 2, 3]]
=
[2, 3, 4]
这也是 <$>
和 <*>
运算符协同工作以对多个操作的结果应用多参数函数的方式,例如:
(*) <$> [1..5] <*> [1..5]
=
((*) <$> [1..5]) <*> [1..5]
=
[(1 *), (2 *), (3 *), (4 *), (5 *)] <*> [1..5]
=
[ (1 *) 1, (2 *) 1, (3 *) 1, (4 *) 1, (5 *) 1
, (1 *) 2, (2 *) 2, (3 *) 2, (4 *) 2, (5 *) 2
, (1 *) 3, (2 *) 3, (3 *) 3, (4 *) 3, (5 *) 3
, (1 *) 4, (2 *) 4, (3 *) 4, (4 *) 4, (5 *) 4
, (1 *) 5, (2 *) 5, (3 *) 5, (4 *) 5, (5 *) 5
]
=
[ 1, 2, 3, 4, 5
, 2, 4, 6, 8, 10
, 3, 6, 9, 12, 15
, 4, 8, 12, 16, 20
, 5, 10, 15, 20, 25
]
这也可以写成pure (*) <*> [1..5] <*> [1..5]
。
<$>
构建一个动作(在本例中为列表)返回(包含)部分应用的函数,<*>
获取这些函数并将它们应用于参数。 (如果函数接受两个以上的参数,那么这也可能导致部分应用函数,可以通过 <*>
的另一个应用程序将其应用于更多参数。)
同样的法则适用于其他“类似容器”的应用程序,例如 Maybe
或 Either e
(对于某些 e
),以及“类似动作”的应用程序,例如作为 IO
、Cont r
或 Async
.