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。不过,我觉得不值得为了避免控制而改用那种相当复杂的拼写。