Tue Aug 16 16:11:55 CEST 2011
The prerequisites for an Arrow instance are (.) and id from Category,
which gives the basic composition mechanism, and the operations arr
and first. The arr operation simply lifts functions.
arr :: (b -> c) -> a b c
While the first operation provides basic communication
first :: a b c -> a (b, d) (c, d)
I.e it's like using a stack to temporarily stash something away, here
the type d, in order to perform an operation and pop it back. This is
essentially a disguised form of the basic "stack shuffling" mechanism
behind concatenative languages such as Forth.
Apparently the other operations can be derived from arr and first.
The second operation is simply the mirror of first.
second :: a b c -> a (d, b) (d, c)
Parallel composition takes two cables and puts them in the same tube.
(***) :: a b c -> a b' c' -> a (b, b') (c, c')
Fanout takes to cables that come from the same point
(&&&) :: a b c -> a b c' -> a b (c, c')
Note that binary algebraic operations can be applied to arrow outputs
by making tuples and applying lifted curried operations.
I do see that some people think of this as a clumsy interface. I'm
familiar with this kind of structure through working with graphical
data flow languages. And indeed, it's not easy to put this inherently
graphical construct in a textual form. While point-free style can be
quite powerful, it can also require a lot of intricate plumbing that
would be more straightforward to express in an applicative style using
In my first state-space model implementation, I naturally came to the
ssmSer and ssmPar operations, where ssmSer is (.) and ssmPar seems to
be (***) in the Arrow class. I also had lifted functions from
ssmPure. This looks like a complete set.
The new GHC has Arrow notation.