了解Haskell中的箭头 [英] Understanding Arrows in Haskell

查看:206
本文介绍了了解Haskell中的箭头的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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



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

对于这个问题,箭头语法的意思是直观的?

解决方案

请查看 http://www.cs.yale。 edu / homes / hudak / CS429F04 / AFPLectureNotes.pdf ,它解释了Arrows如何在FRP中工作。

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

在FRP中,常量和变量通常表示为忽略其输入的箭头,例如

 十二,十一:: Arrow f => fp Int 
12 = arr(const 12)
eleven = arr(const 11)

功能应用程序随后转换为组合(>>> ):

 < code>#(6-)12 

arr(6-)<< 12

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

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

由于柯里化的原因,我们可能将其视为一个返回函数的函数。所以

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

现在让我们将其应用于常量

  arr(+) - #fa(a  - > a)
<< 12 - #fb Int
:: fb(Int - > Int)

+ ---------- + + ----- + + - ------------ +
| const 12 | ----> | (+)| == | const(+ 12)|
+ ---------- + + ----- + + -------------- +

嘿等,它不起作用。结果仍然是一个返回函数的箭头,但我们期望类似于 f Int Int 我们注意到,箭头中的currying失败了,因为只允许合成。因此,我们必须首先解除函数

  uncurry ::(a  - > b  - > c) - > ((a,b) - > c)

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

然后我们有箭头

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

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

然后可以正确执行添加。

 (arr.uncurry)(+) - #f(a,a)a 
<< 12 - #f b Int
&&& eleven - #f b Int
:: f b a

+ -------- +
| const 12 | -----。
+ -------- + | + ----- + + ---------- +
&&& ====> | (+)| == | const 23 |
+ -------- + | + ----- + + ---------- +
| const 11 | -----'
+ -------- +

(现在,为什么我们不需要像&&& amp ; 对于具有3个参数的函数的3元组,因为可以使用((a,b),c))。 p>




编辑:从John Hughes的原始文章将单子推广到箭头 p>


4.1箭头和成对



然而,即使在monad中运算符 return >> = 是我们开始编写有用代码所需的全部内容,对于类似运算符 arr >>> 是不够的。即使是我们前面看到的简单的monadic加法函数

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

但用箭头表示。我们看到类似的定义应该采取以下形式:

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

必须将 f g 。唯一可用的排序算子是>>> ,但是 f g 没有合适的类型组成。事实上, add 函数需要在整个计算过程中保存类型 b 的输入 f ,以便能够为 g 提供相同的输入。同样,必须在计算 g 时保存 f 的结果,以便最终可以将两个结果相加并返回。目前引入的箭头组合器让我们无法在另一个计算中保存一个值,所以我们别无选择,只能引入另一个组合器。



I've been trying to get a grip on arrows since they're the basis of most FRP implementations. I think I understand the basic idea - they're related to monads but store static information at each bind operator so you can walk through a chain of arrows and look at the static information without having to evaluate the whole arrow.

But I get lost at the point where we start discussing first, second, and swap. What do 2-tuples have to do with arrows? Tutorials present the tuple stuff as if it were an obvious next step, but I'm not really seeing the connection.

For that matter, what does the arrow syntax mean intuitively?

解决方案

Please take a look in http://www.cs.yale.edu/homes/hudak/CS429F04/AFPLectureNotes.pdf, which explains how Arrows work in FRP.

2-tuples are used in defining Arrows because it's needed to represent an arrowized function taking 2 arguments.

In FRP, constants and variables are often represented as arrows which ignores its "input", e.g.

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

Function applications are then turned into compositions (>>>):

# (6-) 12

arr (6-) <<< twelve

Now how do we turn a 2-argument function into an arrow? For instance

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

due to currying we may treat this as a function returning a function. So

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

now let's apply it to a constant

arr (+)             -- # f     a (a -> a)
  <<< twelve        -- # f b Int
                      :: f b     (Int -> Int)

+----------+      +-----+      +--------------+
| const 12 |----> | (+) |  ==  | const (+ 12) |
+----------+      +-----+      +--------------+

hey wait, it doesn't work. The result is still an arrow that returns a function, but we expect something akin to f Int Int. We notice that currying fails in Arrow because only composition is allowed. Therefore we must uncurry the function first

uncurry :: (a -> b -> c) -> ((a, b) -> c)

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

Then we have the arrow

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

The 2-tuple arises because of this. Then the bunch functions like &&& are needed to deal with these 2-tuples.

(&&&) :: f a b -> f a d -> f a (b, d)

then the addition can be correctly performed.

(arr.uncurry) (+)        -- # f   (a,    a) a
  <<<     twelve         -- # f b  Int
      &&& eleven         -- # f b      Int
                           :: f b           a

+--------+
|const 12|-----.
+--------+     |       +-----+      +----------+
              &&&====> | (+) |  ==  | const 23 |
+--------+     |       +-----+      +----------+
|const 11|-----'
+--------+

(Now, why don't we need things like &&&& for 3-tuples for functions having 3 arguments? Because a ((a,b),c) can be used instead.)


Edit: From John Hughes's original paper Generalising Monads to Arrows, it states the reason as

4.1 Arrows and Pairs

However, even though in case of monads the operators return and >>= are all we need to begin writing useful code, for arrows the analogous operators arr and >>> are not sufficient. Even the simple monadic addition function that we saw earlier

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

cannot yet be expressed in an arrow form. Making dependence on an input explicit, we see that an analogous definition should take the form

   add :: Arrow a => a b Int -> a b Int -> a b Int
   add f g = ...

where we must combine f and g in sequence. The only sequencing operator available is >>>, but f and g do not have the right types to be composed. Indeed, the add function needs to save the input of type b across the computation of f, so as to be able to supply the same input to g. Likewise the result of f must be saved across the computation of g, so that the two results can eventually be added together and returned. The arrow combinators so far introduced give us no way to save a value across another computation, and so we have no alternative but to introduce another combinator.

这篇关于了解Haskell中的箭头的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆