my user page


Arrows are a generalization of monads: every monad gives rise to an arrow, but not all arrows give rise to monads. They serve much the same purpose as monads -- providing a common structure for libraries -- but are more general. In particular they allow notions of computation that may be partially static (independent of the input) or may take multiple inputs. If your application works fine with monads, you might as well stick with them. But if you're using a structure that's very like a monad, but isn't one, maybe it's an arrow.


箭头(arrow)是单子(monad)的抽象:所有的单子都是箭头,但不是所有的箭头都是单子他们都为一个目的设计 -- 提供一个通用的结构来构建库 --但箭头抽象度更高。 特别的,箭头允许为那写非全静态的(取决于输入)或者是多输入的计算做上记号。 如果能用单子写出不错的程序,你会喜欢上它的。但如果你只是写出了一些像单子的东西,那它可能是箭头

proc and the arrow tailEdit

Let's begin by getting to grips with the arrows notation. We'll work with the simplest possible arrow there is (the function) and build some toy programs strictly in the aims of getting acquainted with the syntax.

Fire up your text editor and create a Haskell file, say toyArrows.hs:

{-# LANGUAGE Arrows #-}

import Control.Arrow (returnA)

idA :: a -> a
idA = proc a -> returnA -< a

plusOne :: Int -> Int
plusOne = proc a -> returnA -< (a+1)

These are our first two arrows. The first is the identity function in arrow form, and second, slightly more exciting, is an arrow that adds one to its input. Load this up in GHCi, using the -XArrows extension and see what happens.

% ghci -XArrows toyArrows.hs   
   ___         ___ _
  / _ \ /\  /\/ __(_)
 / /_\// /_/ / /  | |      GHC Interactive, version 6.4.1, for Haskell 98.
/ /_\\/ __  / /___| |
\____/\/ /_/\____/|_|      Type :? for help.

Loading package base-1.0 ... linking ... done.
Compiling Main             ( toyArrows.hs, interpreted )
Ok, modules loaded: Main.
*Main> idA 3
*Main> idA "foo"
*Main> plusOne 3
*Main> plusOne 100

Thrilling indeed. Up to now, we have seen three new constructs in the arrow notation:

  • the keyword proc
  • -<
  • the imported function returnA

Now that we know how to add one to a value, let's try something twice as difficult: adding TWO:

 plusOne = proc a -> returnA -< (a+1)
 plusTwo = proc a -> plusOne -< (a+1)

One simple approach is to feed (a+1) as input into the plusOne arrow. Note the similarity between plusOne and plusTwo. You should notice that there is a basic pattern here which goes a little something like this: proc FOO -> SOME_ARROW -< (SOMETHING_WITH_FOO)

  1. plusOne is an arrow, so by the pattern above returnA must be an arrow too. What do you think returnA does?

do notationEdit

Our current implementation of plusTwo is rather disappointing actually... shouldn't it just be plusOne twice? We can do better, but to do so, we need to introduce the do notation:

 plusTwoBis = 
  proc a -> do b <- plusOne -< a
               plusOne -< b

Now try this out in GHCi:

Prelude> :r
Compiling Main             ( toyArrows.hs, interpreted )
Ok, modules loaded: Main.
*Main> plusTwoBis 5

You can use this do notation to build up sequences as long as you would like:

plusFive =
 proc a -> do b <- plusOne -< a
              c <- plusOne -< b
              d <- plusOne -< c
              e <- plusOne -< d
              plusOne -< e

Monads and arrowsEdit

FIXME: I'm no longer sure, but I believe the intention here was to show what the difference is having this proc notation instead to just a regular chain of dos