haskell 中的箭头和函数有何不同?

How are Arrows and Functions different in haskell?

我学习和搜索了一段时间的 Arrows,我对 Arrow 的必要性有点困惑 class。 据我所知,Arrowclass是函数的抽象,ArrowA a b c表示某物接受b类型的输入和c类型的输出。此外,它还提供了几个基本操作,如 >>>arrfirst.

但是,我找不到 b -> c 类型的标准函数和 A a b c 类型的 Arrow 之间的任何区别。在我看来,first>>>可以用\(b, c) -> (f b, c)(.)代替。另外,由于箭头内部的每个计算都是用函数表示的,如果我们用这些函数替换箭头,我认为不会有任何区别。

简而言之,我认为Arrows的计算图的每个节点(类似于https://www.haskell.org/arrows/syntax.html中的东西)都可以用Haskell的标准函数代替。如果是真的,为什么我们用箭头而不是函数?

那是因为您只查看 Arrow(->) 实例。其他类型也可以声明Arrow的实例,其中操作比较复杂。例如:

instance Monad m => Arrow (Kleisli m) where
    arr f = Kleisli (return . f)
    first (Kleisli f) = Kleisli (\ ~(b,d) -> f b >>= \c -> return (c,d))
    second (Kleisli f) = Kleisli (\ ~(d,b) -> f b >>= \c -> return (d,c))

拥有遵守特定法则的抽象 允许您进行泛型编程。您可以在没有任何 type-classes 的情况下进行编程(没有 monads、applicatives、没有 equality/ordering 等),但这会很不方便,因为您将无法编写利用这些属性。

就像你说你不想要 Ord 实例一样,然后你必须为你可以订购的每种数据类型分别重写 Set 的实现。

Arrow 的要点是描述

的计算
  • 接受输入,
  • 产生输出,并且
  • 中间有一定的(效果是口语表达)。

所以箭头 A b c 不是函数 a -> b。箭头很可能在内部作为函数实现,但更复杂,实现 Arrow 接口的目的是描述(除其他事项外)它们是如何组合的。

专门针对箭头,您拥有 arrow notation that allows you to use the same notation for any valid Arrow. To give an example, in the netwire package the Wire 数据类型实现 Arrow,因此您可以使用箭头表示法,以及所有适用于箭头的实用函数。如果没有实例,您将不得不使用一些特定于 netwire 的语法,或者只使用 netwire 提供的功能。

举个例子:State monad对应的箭头是a -> s -> (b, s)。但是两个这样的函数不使用 (.) 组合。您需要描述它们的组成,而这正是 Arrow 所做的。


更新: 可组合性有多种概念,但我猜你指的是类似函数的组合。是的,这种可组合性来自 ArrowCategory superclass,它定义了身份和组合。

Arrow的另一部分来自Strong profunctor as I've recently learned from (尽管这没有在类型-class层次结构中捕获,因为Profunctor类型class 比 Arrow 年轻)。 Profunctors 允许通过来自 "both sides" 的纯计算进行修改,参见 Profunctor 中的 lmap/rmap/dimap。对于箭头,我们有 (<<^)(^>>),它们使用 arr>>> 表示,通过将来自任一侧的箭头与使用 arr 构造的纯箭头组合而成.

最后箭 强度 wrt (,),被 first :: Arrow a => a b c -> a (b, d) (c, d) 捕获。这意味着我们可以只在输入的一部分上使用箭头,而传递另一部分不变。这允许用 "parallel wires" 构造 "circuits" - 如果没有 first 就不可能保存一部分计算的输出并在以后的某个地方使用它。

一个很好的练习是绘制一个表示计算的电路,然后尝试使用 Arrow primitives/utilities 或箭头语法符号来表达它。您会发现 first(或 ***)对此至关重要。

请参阅 Arrows can multitask 以获得漂亮的操作图。

更多理论背景 Arrows are Strong Monads 可能很有趣(我还没读过)。