理解Haskell中的箭头

我一直试图抓住箭头,因为他们是大多数玻璃钢实施的基础。 我想我理解了这个基本思想 – 它们与单子有关,但是在每个绑定操作符中存储静态信息,这样你就可以通过一连串箭头来查看静态信息,而无需评估整个箭头。

但是,我们开始讨论第一,第二和交换的时候,我迷失了方向。 二元组与箭头有什么关系? 教程提出了元组的东西,好像它是一个明显的下一步,但我没有真正看到连接。

对于这个问题,箭头语法是什么意思?

请查看homes/hudak/CS429F04/AFPLectureNotes.pdf ,其中解释了箭头如何在FRP中工作。

2元组用于定义箭头,因为它需要表示带2个参数的箭头函数。

在FRP中,常量和variables通常表示为忽略其“input”的箭头,例如

twelve, eleven :: Arrow f => fp Int twelve = arr (const 12) eleven = arr (const 11) 

function应用程序然后变成组合( >>> ):

 # (6-) 12 arr (6-) <<< twelve 

现在我们如何将一个2参数函数转换成一个箭头? 例如

 (+) :: Num a => a -> a -> a 

由于咖喱,我们可以把它作为一个函数返回一个函数。 所以

 arr (+) :: (Arrow f, Num a) => fa (a -> a) 

现在让我们把它应用到一个常量

 arr (+) -- # fa (a -> a) <<< twelve -- # fb Int :: fb (Int -> Int) +----------+ +-----+ +--------------+ | const 12 |----> | (+) | == | const (+ 12) | +----------+ +-----+ +--------------+ 

嘿等,这是行不通的。 结果仍然是一个返回函数的箭头,但我们期望类似于f Int Int东西。 我们注意到,咖啡因在箭头中失败,因为只有合成是允许的。 因此,我们必须首先解除function

 uncurry :: (a -> b -> c) -> ((a, b) -> c) uncurry (+) :: Num a => (a, a) -> a 

然后我们有箭头

 (arr.uncurry) (+) :: (Num a, Arrow f) => f (a, a) a 

二元组因此而出现。 然后,像&&&这样的函数需要处理这些2元组。

 (&&&) :: fab -> fad -> fa (b, d) 

那么可以正确执行添加。

 (arr.uncurry) (+) -- # f (a, a) a <<< twelve -- # fb Int &&& eleven -- # fb Int :: fba +--------+ |const 12|-----. +--------+ | +-----+ +----------+ &&&====> | (+) | == | const 23 | +--------+ | +-----+ +----------+ |const 11|-----' +--------+ 

(现在,为什么我们不需要像3元组的&&&&这样的函数有3个参数?因为可以用((a,b),c)代替)。


编辑:从约翰休斯的原始文件概括Monads箭头 ,它说明原因

4.1箭头和对

但是,即使在monad的情况下,运算符return >>=我们都需要开始编写有用的代码,对于箭头来说,类似的运算符arr>>>是不够的。 即使是我们前面看到的简单的monadic加法函数

  add :: Monad m => m Int -> m Int -> m Int add xy = x >>= \u -> (y >>= \v -> return (u + v)) 

还不能用箭头表示。 明确地依赖于input,我们看到类似的定义应该采取这种forms

  add :: Arrow a => ab Int -> ab Int -> ab Int add fg = ... 

我们必须按顺序结合fg 。 唯一可用的sorting算子是>>> ,但是fg没有合适的types组成。 事实上, add函数需要在f的计算中保存typesb 的input ,以便能够向g提供相同的input。 同样, f的结果必须在g的计算中保存,以便两个结果最终可以相加并返回。 目前引入的箭头组合器让我们无法在另一个计算上保存一个值,所以我们别无select,只能引入另一个组合器。

什么箭? 你的意思是在(\x -> func x)箭头,或者如[ x*x | x <- [1..10]] [ x*x | x <- [1..10]]

前者是lamba应用程序:在lambda语句中遵循符号声明的点; 如果你解开语义,它基本上把let x = some_value in func x中的let x = some_value in func x转换成它自己的函数:定义一个调用其操作数func的函数。 第二类似于集合论:从1到10(含)范围内的自然数集合中取x。