问题 Arrows是功能的真正概括吗?


箭头通常被描述为函数的泛化(仅静态生成函数,即不支持部分应用/闭包)。但是,至少在Haskell中建模时看看Arrows,我看不出它们如何能够推广返回单个结果的多个参数的函数(通常可能不是元组的结果)。我试图设想如何仅使用箭头界面,可以得到一个箭头组合,产生一个通常可能不是元组的结果。有没有办法做到这一点,或者这是对箭头类型的力量的故意限制?

根据我的理解,箭头提供了组成静态(可能是并行)管道的能力,但是它们不能将输出的元组“折叠”成单个最终结果。我错了还是错过了什么?


9852
2018-04-14 00:08


起源

你看过了吗? ArrowApply? - Daniel Wagner
ArrowApply确实解决了多个参数的问题,但它将部分应用/闭包的额外功能带入了混合...... - Dr DR
说实话,我不确定我理解这个问题。因为函数实际上是箭头(有一个 instance Arrow (->)很明显,箭头概括了函数。那么“真正的概括”是什么意思呢?如果箭头成为函数的“真正”推广,那么情况会怎样? - Daniel Wagner
我承认这个问题可能没有意义,可能反映了我的误解。我无法看到Arrow界面如何支持多个参数的箭头组合,但正如下面的答案指出的那样,这不是问题,只需构造一个箭头 Arrow (a,b) c并且组成。我认为这在某种意义上是作弊,因为它取决于将某种功能(一种带元组的功能)提升到箭头中,但我想这不是一个真正的问题。 - Dr DR
@Daniel Wagner我的意思是“真正的概括”,非正式意义上的“概括是否捕获了我们想要的一切?”。我知道Haskell将函数类型定义为Arrow类型的一个实例。然而,无论出于何种原因,我没有想到明确定义其输入类型是元组的箭头是完全合理的,就像用元组作为参数声明函数(即非curried多参数函数)一样有效。你认为我应该重新提出这个问题吗? - Dr DR


答案:


我看不出它们如何能够推广返回单个结果的多个参数的函数

只需输入类型为元组,输出为普通值。例如,拿箭头

plus :: a (num, num) num
let plus = arr (\(a, b) -> a + b) -- arr (uncurry (+))

或者,您可以使用“嵌套箭头” - 具有多个参数的curried函数只是一个返回函数的函数。所以我们有一个箭头,其结果是另一个箭头:

plus :: a num (a num num)
let plus = arr (arr . (+))

并使用它,我们需要一个 ArrowApply 实例。首先,您将箭头与另一个箭头组合在一起,从输入中创建第二个参数

plusWithIncrement :: a num (a num num, num)
let plusWithIncrement = plus &&& arr (+1)

然后你可以运行它

plusWithIncrement >>> app :: a num num

(这是一种过于复杂的写作方式 arr (\x -> x + (x+1))


9
2018-04-14 01:02



由于某种原因我构建了一个带有显式元组类型的箭头作为输入的某种原因让我感到困惑但我意识到这是照常营业。正如你所指出的,curried方法需要ArrowApply,它显着增加了Arrow类型的强大功能:它们现在可以像lambda演算中的函数一样动态构造。 - Dr DR


你可以考虑类型的功能

f :: a -> b -> c

作为一个取值类型的函数 a 并生成另一种类型的函数 b -> c。换一种说法,

f :: a -> (b -> c)

箭头的推广非常简单:

f :: Arrow a (Arrow b c)

为了用多个变量做函数组合,你必须做一些疯狂的语义 - 用 (.) 运营商,或 (<<<) 对于箭头。同样的道理 使具有多个参数的函数无点繁琐 阻止语法以这种方式表达箭头,这就是为什么有这么多组合使用元组的原因。此外,没有什么能阻止你定义一个将元组映射到值的箭头。该 arr 函数将任意函数转换为箭头!

f :: (a, b) -> c
af :: Arrow (a, b) c
af = arr f

6
2018-04-14 00:42



嵌套箭头方法需要ArrowApply但是当你指出我真正需要的是一个箭头接受一个元组。我接受了Bergi的回答只是因为它更明确地说明了需要应用函数来评估的嵌套箭头。 - Dr DR