本文介绍了什么是箭头,我该如何使用?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我试图学习箭头的含义,但我不理解它们。

I tried to learn the meaning of arrows, but I didn't understand them.

我使用了Wikibooks教程。我认为Wikibook的问题主要是它似乎是为已经理解该主题的人编写的。

I used the Wikibooks tutorial. I think Wikibook's problem is mainly that it seems to be written for somebody who already understands the topic.

有人可以解释什么是箭头以及如何使用箭头吗?

Can somebody explain what arrows are and how I can use them?

推荐答案

我不知道教程,但是如果您看一些具体的例子,我认为最容易理解箭头。我学习如何使用箭头的最大问题是,这些教程或示例均未真正显示如何使用箭头,以及如何组合箭头。因此,考虑到这一点,这是我的迷你教程。我将检查两个不同的箭头:函数和用户定义的箭头类型 MyArr

I don't know a tutorial, but I think it's easiest to understand arrows if you look at some concrete examples. The biggest problem I had learning how to use arrows was that none of the tutorials or examples actually show how to use arrows, just how to compose them. So, with that in mind, here's my mini-tutorial. I'll examine two different arrows: functions and a user-defined arrow type MyArr.

-- type representing a computation
data MyArr b c = MyArr (b -> (c,MyArr b c))

1)箭头是从指定类型的输入到指定类型的输出的计算。箭头类型类采用三个类型参数:箭头类型,输入类型和输出类型。查看箭头实例的实例头,我们发现:

1) An Arrow is a calculation from input of a specified type to output of a specified type. The arrow typeclass takes three type arguments: the arrow type, the input type, and the output type. Looking at the instance head for arrow instances we find:

instance Arrow (->) b c where
instance Arrow MyArr b c where

The Arrow((->) MyArr )是计算的抽象。

The Arrow (either (->) or MyArr) is an abstraction of a computation.

对于函数 b-> c b 是输入, c 是输出。

对于 MyArr bc b 是输入,而 c

For a function b -> c, b is the input and c is the output.
For a MyArr b c, b is the input and c is the output.

2)要实际运行箭头计算,请使用特定于箭头类型的函数。对于函数,您只需将函数应用于参数。对于其他箭头,需要有一个单独的函数(就像monads的 runIdentity runState 等一样)。

2) To actually run an arrow computation, you use a function specific to your arrow type. For functions you simply apply the function to an argument. For other arrows, there needs to be a separate function (just like runIdentity, runState, etc. for monads).

-- run a function arrow
runF :: (b -> c) -> b -> c
runF = id

-- run a MyArr arrow, discarding the remaining computation
runMyArr :: MyArr b c -> b -> c
runMyArr (MyArr step) = fst . step

3)箭头通常用于处理输入列表。对于功能,这些可以并行完成,但对于某些给定步骤中的某些箭头,其输出取决于先前的输入(例如,保持连续的输入总数)。

3) Arrows are frequently used to process a list of inputs. For functions these can be done in parallel, but for some arrows output at any given step depends upon previous inputs (e.g. keeping a running total of inputs).

-- run a function arrow over multiple inputs
runFList :: (b -> c) -> [b] -> [c]
runFList f = map f

-- run a MyArr over multiple inputs.
-- Each step of the computation gives the next step to use
runMyArrList :: MyArr b c -> [b] -> [c]
runMyArrList _ [] = []
runMyArrList (MyArr step) (b:bs) = let (this, step') = step b
                                   in this : runMyArrList step' bs

这是Arrow有用的原因之一。它们提供了一种计算模型,该模型可以隐式地使用状态,而无需将状态暴露给程序员。程序员可以使用箭头化的计算,并将它们组合起来以创建复杂的系统。

This is one reason Arrows are useful. They provide a computation model that can implicitly make use of state without ever exposing that state to the programmer. The programmer can use arrowized computations and combine them to create sophisticated systems.

这里是一个MyArr,它可以统计收到的输入数量:

Here's a MyArr that keeps count of the number of inputs it has received:

-- count the number of inputs received:
count :: MyArr b Int
count = count' 0
  where
    count' n = MyArr (\_ -> (n+1, count' (n+1)))

现在,函数 runMyArrList count 将以列表长度n作为输入,并返回从1到n的整数列表。

Now the function runMyArrList count will take a list length n as input and return a list of Ints from 1 to n.

请注意,我们仍未使用任何箭头函数,即Arrow类方法或根据它们编写的函数。

Note that we still haven't used any "arrow" functions, that is either Arrow class methods or functions written in terms of them.

4)上面的大多数代码特定于每个Arrow实例[1]。 Control.Arrow (和 Control.Category )中的所有内容都是关于组成箭头以制作新的箭头。如果我们假装Category是Arrow的一部分,而不是一个单独的类:

4) Most of the code above is specific to each Arrow instance[1]. Everything in Control.Arrow (and Control.Category) is about composing arrows to make new arrows. If we pretend that Category is part of Arrow instead of a separate class:

-- combine two arrows in sequence
>>> :: Arrow a => a b c -> a c d -> a b d

-- the function arrow instance
-- >>> :: (b -> c) -> (c -> d) -> (b -> d)
-- this is just flip (.)

-- MyArr instance
-- >>> :: MyArr b c -> MyArr c d -> MyArr b d

>>>

The >>> function takes two arrows and uses the output of the first as input to the second.

这里是另一个运算符,通常称为扇出:

Here's another operator, commonly called "fanout":

-- &&& applies two arrows to a single input in parallel
&&& :: Arrow a => a b c -> a b c' -> a b (c,c')

-- function instance type
-- &&& :: (b -> c) -> (b -> c') -> (b -> (c,c'))

-- MyArr instance type
-- &&& :: MyArr b c -> MyArr b c' -> MyArr b (c,c')

-- first and second omitted for brevity, see the accepted answer from KennyTM's link
-- for further details.

由于 Control.Arrow 提供了一种方法结合计算,这是一个示例:

Since Control.Arrow provides a means to combine computations, here's one example:

-- function that, given an input n, returns "n+1" and "n*2"
calc1 :: Int -> (Int,Int)
calc1 = (+1) &&& (*2)

我经常发现像 calc1 在复杂的折叠或对指针进行操作的函数中很有用。

I've frequently found functions like calc1 useful in complicated folds, or functions that operate on pointers for example.

Monad 类型类为我们提供了一种使用> = 函数将单子计算合并为单个新单子计算的方法。类似地, Arrow 类为我们提供了使用一些原始函数( first arr *** ,其中>>> id (来自Control.Category)。同样类似于Monads的问题是箭的作用是什么?通常无法回答。

The Monad type class provides us with a means to combine monadic computations into a single new monadic computation using the >>= function. Similarly, the Arrow class provides us with means to combine arrowized computations into a single new arrowized computation using a few primitive functions (first, arr, and ***, with >>> and id from Control.Category). Also similar to Monads, the question of "What does an arrow do?" can't be generally answered. It depends on the arrow.

不幸的是,我不知道许多野外箭头实例的例子。功能和FRP似乎是最常见的应用程序。 HXT是唯一想到的其他重要用法。

Unfortunately I don't know of many examples of arrow instances in the wild. Functions and FRP seem to be the most common applications. HXT is the only other significant usage that comes to mind.

[1]除 count 以外。可以编写对 ArrowLoop 的任何实例执行相同操作的计数函数。

[1] Except count. It's possible to write a count function that does the same thing for any instance of ArrowLoop.

这篇关于什么是箭头,我该如何使用?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

08-19 14:22