[英]x <*> y <$> z in Haskell
我正在尝试理解一些Haskell源代码,我有时会遇到这种结构:
x <*> y <$> z
例如
(+) <*> (+1) <$> a
有人可以向我解释这个结构吗? 我得到它转换为fmap a (+ a + 1)
,但我无法建立连接
让我们从:
x <*> y <$> z
添加括号,它变为:
(x <*> y) <$> z
鉴于(<$>) :: Functor f => (a -> b) -> fa -> fb
,我们有:
x <*> y :: a -> b
z :: Functor f => f a
鉴于(<*>) :: Applicative g => g (c -> d) -> gc -> gd
,我们有:
x :: Applicative g => g (c -> d)
y :: Applicative g => g c
x <*> y :: Applicative g => g d
结合最后几个结果,我们得到:
g d ~ a -> b
g ~ (->) a
d ~ b
x :: a -> c -> b
y :: a -> c
x <*> y :: a -> b
因此:
(\x y z -> x <*> y <$> z) :: Functor f => (a -> c -> b) -> (a -> c) -> f a -> f b
现在知道正在使用函数实例中的(<*>)
,我们也可以替换它的定义:
x <*> y <$> z
(\r -> x r (y r)) <$> z
在你的例子中, x = (+)
, y = (+1)
和z = a
,所以我们得到......
(\r -> r + (r + 1)) <$> a
......这增加了在每个值a
给自己加一个:
GHCi> (+) <*> (+1) <$> [0..3]
[1,3,5,7]
GHCi> ((+) <*> (+1) <$> (*5)) 2
21
因此,在x <*> y <$> z
,即fmap (x<*>y) z
,您将函数x<*>y
应用于functor-value z
。 <*>
实际上对fmapping一无所知 - 两个运算符在完全独立的仿函数上工作! 这是在这里实现的第一件重要事情。
接下来是,如果x<*>y
的结果是函数,那么<*>
的Applicative
实例实际上是函数函子 。 我希望人们会停止使用它,因为它确实是一个更令人困惑的实例,通常不是最好的抽象选择。
具体地说, f<*>g
只是组成函数f
和g
一种巧妙方式,同时也将初始输入直接传递给f
。 它起作用:
(<*>) :: (f ~ (x->))
=> f (a -> b) -> f a -> f b
即
(<*>) :: (x ->(a -> b)) -> (x -> a) -> (x -> b)
≡ (x -> a -> b) -> (x -> a) -> x -> b
(f <*> g) x = f x $ g x
就数据流而言,就是这个操作:
────┬─────▶ f ──▶
│ │
└─▶ g ──┘
我宁愿用箭头组合器表达这个:
┌───id──┐
────&&& uncurry f ──▶
└─▶ g ──┘
所以f<*>g ≡ id &&& g >>> uncurry f
。 当然,这不是那么紧凑,事实上比明确的lambda版本更简洁\\x -> fx $ gx
,坦率地说这可能是最好的。 然而,箭头版本是这三个版本中最常见的版本,并且可以说是表达最佳状态。 它如此冗长的主要原因是,currying在这里并不合适; 我们可以定义一个运算符
(≻>>) :: (x->(a,b)) -> (a->b->c) -> x -> c
g≻>>h = uncurry h . g
然后
x <*> y <$> z
≡ fmap (id &&& y ≻>> x) z
≡ fmap (\ξ -> x ξ $ y ξ) z
例如,我们有
(+) <*> (+1) <$> a
≡ fmap (id &&& (+1) ≻>> (+)) z
≡ fmap (\x -> 1 + x+1) z
≡ fmap (+2) z
我首先误读了你的问题。 模式<$>
<*>
比您的<*>
<$>
更常见,以下地址表示......可能对其他人有用。
f <$> y <*> z
也可以写成liftA2 fyz
,而liftA2
比同等的<*>
更容易理解。
liftA2 :: (a -> b -> c) -> f a -> f b -> f c
它的作用是,它在值上采用组合器函数,并从中生成容器上的组合器函数。 它类似于一个位zipWith
除了列表实例,它不仅结合了每个元素a
与在相应的元素列表b
列表中,但在结合每个元素a
清单,在所有要素一次b
名单,并连接结果。
Prelude> Control.Applicative.liftA2 (+) [0,10..30] [0..3]
[0,1,2,3,10,11,12,13,20,21,22,23,30,31,32,33]
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.