理解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 = ...
我们必须按顺序结合
f
和g
。 唯一可用的sorting算子是>>>
,但是f
和g
没有合适的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。