Haskell Control.Arrow vs Data.Tuple.Extra

Haskell Control.Arrow vs Data.Tuple.Extra,haskell,Haskell,我经常使用Data.Tuple.Extra库的以下函数:第一个,第二个,***,&&&,以及二者 Control.Arrow中有等效的(?)函数。事实上,我更喜欢Data.Tuple.Extra,因为我完全不懂Control.Arrow的文档 使用控件.Arrow(例如从性能角度来看)有什么好处吗?我不熟悉Data.Tuple.Extra,但从文档来看,它似乎提供了与控件.Arrow基本相同的功能。其文件甚至指出: 其中一些功能在控制箭头模块中可用 您可以使用控件轻松实现复制和这两个功能。箭头:

我经常使用
Data.Tuple.Extra
库的以下函数:
第一个
第二个
***
&&&
,以及
二者

Control.Arrow中有等效的(?)函数。事实上,我更喜欢
Data.Tuple.Extra
,因为我完全不懂
Control.Arrow
的文档


使用
控件.Arrow(例如从性能角度来看)有什么好处吗?

我不熟悉
Data.Tuple.Extra
,但从文档来看,它似乎提供了与
控件.Arrow
基本相同的功能。其文件甚至指出:

其中一些功能在
控制箭头模块中可用

您可以使用
控件轻松实现
复制
这两个功能。箭头

dupe = id &&& id
both f = first f >>> second f
示例:

Prelude Control.Arrow> dupe 42
(42,42)
Prelude Control.Arrow> both (+1) (41, 1336)
(42,1337)
使用
控件.Arrow有什么好处吗?它更一般,因为它是基于
Arrow
类型类的,它同样源于范畴理论。。。此外,该模块包含在
base
包中,因此始终可用

更一般地说,这里定义的
的类型是
箭头a=>adc->a(d,d)(c,c)
,这意味着您可以将它与任何
箭头一起使用,而不仅仅是“基本”函数。例如,考虑<代码> Kasclii < /Cord>箭头。< /P>
Prelude
中的
print
函数的类型为
Show a=>a->IO()
,由于
IO
是一个
Monad
,您可以将其设为
Kleisli
实例,应用
两者,并成对运行:

Prelude Control.Arrow> runKleisli (both $ Kleisli print) (42, 1337)
42
1337
((),())
我不知道这个特定的例子在现实生活中是否有用,但它证明了
两者的这种实现更加通用


顺便说一句,对也是
Bifunctor
实例,因此您也可以从
Data.Bifunctor
使用
first
second
。您可以用
Bifunctor
来定义

Prelude Data.Bifunctor> both f = bimap f f
Prelude Data.Bifunctor> :t both
both :: Bifunctor p => (a -> d) -> p a a -> p d d
Prelude Data.Bifunctor> both (+2) (40, 1335)
(42,1337)
Prelude Data.Bifunctor> both (*2) $ Right 21
Right 42
Prelude Data.Bifunctor> both (*2) $ Left 8
Left 16
请注意,由于这在任何
Bifunctor
上都起作用,因此除了一对之外,它在
上也起作用


在大多数Haskell用例中,无论您是否使用
数据.Tuple.Extra.first
控件.Arrow.first
数据.bifuntor
,都不会从
数据.bifuntor>中获得
***
&&&&
,但是…

在大多数Haskell用例中,无论您使用的是
数据.Tuple.Extra.first
还是
控件.Arrow.first都将用作

first :: (b -> c) -> (b,d) -> (c,d)
…同样,对于
/
***
/
&&
Arrow
Bifunctor
版本都以不同的方式更为通用,但通常很可能只考虑标准元组/函子的泛化情况

从实用的角度讲,我建议使用
箭头
版本仅仅是因为它们在
base
中。(哦,我刚刚注意到,
Bifunctor
现在也在
base
中,仅此而已……)可以说,
Arrow
也是比
Bifunctor
更好的泛化,因为它允许实际离开Hask类别。不幸的是,
Control.Arrow
本身并没有真正允许更多有趣的类别——它们大体上可以归结为Kleisli/Cokleisli类别(即穿着不同服装的单子),对于那些只使用
do
符号等更为实际

但是有许多数学类别不是
Control.Category.Category
的实例,因为它们不允许在任何Haskell类型之间进行映射,只允许具有特定属性的类型。一个例子是VectK,这是一类具有线性映射作为态射的向量空间。在这个类别中,
是矩阵乘法,
***
是块矩阵对角叠加,
&&
是垂直串联。IMO非常好,特别是因为它完全避免了在Matlab、NumPy或hmatrix中进行运行时维度检查的问题——所有这些都是编译器已经完成的——而且它甚至支持无限维向量空间


正如我所说,它只适用于特定的类型,而标准的
类别
/
箭头
类无法表达这些类型。实际上,用Haskell来表达它非常容易,因此我已经使用了,用于在中实现VectK

我在
控件方面的问题。Arrow
是我不理解类型。例如,
arr::(b->c)->abc
这是什么意思,
abc
?这对我来说很奇怪。把它读作
b`a`c
,通常是简单的
b->c
。嗯,好的。。我会试试。@StéphaneLaurent FWIW,我把
ab c
读作从b到c的箭头。如果能够给类型参数一个操作符作为名称,那就太好了:
arr::arrow(~>)=>(a->b)->a~>b
,也就是说:arr将函数从
a
转换为
b
,并将其转换为从
a
的箭头。毕竟,它们是箭头,应该用箭头来表示。
(***)
函数是
bimap
元组(无中缀)。FWIW,
(&&&&)
函数是
liftA2(,)
,使用函数applicative。不过,我觉得不值得为了避免控制而改用那种相当复杂的拼写。