Haskell 对每个位置的元组分别执行操作

Haskell 对每个位置的元组分别执行操作,haskell,mapping,tuples,Haskell,Mapping,Tuples,我想分别对每个位置的元组执行操作。比如说 pair_of_sums (a1,b1) (a2,b2) = (a1+a2, b1+b2) λ> fst (bimap (+) (+) (3,5)) 10 13 λ> snd (bimap (+) (+) (3,5)) 100 105 还是更一般 sum_and_multiplication (a1,b1) (a2,b2) = (a1+a2, b1*b2) 有没有办法把它缩短?比如: pair_of_sums = xxx (+) sum

我想分别对每个位置的元组执行操作。比如说

pair_of_sums (a1,b1) (a2,b2) = (a1+a2, b1+b2)
λ> fst (bimap (+) (+) (3,5)) 10
13
λ> snd (bimap (+) (+) (3,5)) 100
105
还是更一般

sum_and_multiplication (a1,b1) (a2,b2) = (a1+a2, b1*b2)
有没有办法把它缩短?比如:

pair_of_sums = xxx (+)
sum_and_multiplication = yyy ((+),(*))
以下是它的工作原理:

f                           = ((uncurry (***) .) .) . (***)
f op1 op2                   = uncurry (***) . (op1 *** op2)
f op1 op2  p1       p2      = uncurry (***) ((op1 *** op2) p1) p2
f op1 op2 (x1, y1)  p2      = uncurry (***) ((op1 *** op2) (x1, y1)) p2
f op1 op2 (x1, y1)  p2      = uncurry (***) (op1 x1, op2 y1) p2
f op1 op2 (x1, y1) (x2, y2) = (op1 x1 *** op2 y1) (x2, y2)
f op1 op2 (x1, y1) (x2, y2) = (op1 x1 x2, op2 y1 y2)

一种可能是使用包,包中有一些有用的方法和函数用于处理不同的类型,包括对

pair_of_sums = (<<.>>) . bimap (+) (+)
(本质上,
~
只是告诉Haskell在这里要懒一点。这与我们的目的无关。)

在这种情况下,获取一对函数和一对函数,并将第一对中的每个函数映射到第二对的相应值上。对于这种用法,我们可以将其视为键入
():(a->a',b->b')->(a,b)->(a',b')

我们可以再次查看此函数的源代码,了解此函数如何适用于
(,)
实例:

(f, g) <<.>> (a, b) = (f a, g b)
这为我们提供了一对函数,将给定值添加到该对每个位置的原始值中。比如说

pair_of_sums (a1,b1) (a2,b2) = (a1+a2, b1+b2)
λ> fst (bimap (+) (+) (3,5)) 10
13
λ> snd (bimap (+) (+) (3,5)) 100
105
我们与
()
的组合允许我们将这对函数转换为一个函数,它接受一对并给出一对(与我上面给出的类型签名相匹配)

把这些放在一起,我们可以更详细地了解调用中执行的减少
对求和(3,5)(10100)

一对求和(3,5)(10100)
(().bimap(+)(+)(3,5)(10100)——对_和的定义
(\x->()(bimap(+)(+)x))(3,5)(10100)——的定义
()(bimap(+)(+)(3,5))--
(10100)——函数应用
bimap(+)(+)(3,5)(10100)——从前缀切换到中缀
(++)3、(++)5)(10100)——在为(,)实例应用bimap之后
(++)3 10,(++)5 100--(,)实例的()定义
(13,105)——应用(+)
这与
Applicative
类型类的工作方式非常相似,但它与
Bifunctor
一起工作,而不是
Functor
(实际上,这就是为什么类型类
()
属于
Biapply
bimap
类似于
fmap
()
类似于
()


使用此技术定义这些函数的一个很酷的地方是,它们适用于所有类型构造函数,这些类型构造函数是
Biapply
的实例,而不仅仅是看起来像是overkill的经典定义的
(,)

λ> fst (bimap (+) (+) (3,5)) 10
13
λ> snd (bimap (+) (+) (3,5)) 100
105
pair_of_sums (3, 5) (10, 100)

((<<.>>) . bimap (+) (+))  (3, 5) (10, 100)         -- Definition of pair_of_sums

(\x -> (<<.>>) (bimap (+) (+) x))  (3, 5) (10, 100) -- Definition of (.)

(<<.>>) (bimap (+) (+) (3, 5))                      --
        (10, 100)                                   -- Function application

bimap (+) (+) (3, 5) <<.>> (10, 100)                -- Switch from prefix to infix

((+) 3, (+) 5) <<.>> (10, 100)                      -- After applying bimap for the (,) instance

((+) 3 10, (+) 5 100)                               -- Definition of (<<.>>) for the (,) instance

(13, 105)                                           -- Apply (+)