Who is afraid of arrows, was Re: [Haskell-cafe] ANNOUNCE: Haskell
XML Toolbox Version 9.0.0
gcross at phys.washington.edu
Mon Oct 11 14:48:40 EDT 2010
Thank you for your reply.
On 10/11/10 6:20 AM, Uwe Schmidt wrote:
> I thing, this is not a question of functionality, it's a question of style.
> Of course everything in hxt could have been done with monads,
> but does this also mean: Everything must have been done with monads?
No, but there is no point in using a formalism that adds complexity
without adding functionality. Arrows are more awkward to use than
monads because they were intentionally designed to be less powerful than
monads in order to cover situations in which one could not use a monad.
When your problem is solved by a monad there is no point in using arrows
since an arrow require you to jump through extra hoops to accomplish the
> Arrows are a generalisation of functions, so if you know all about working
> with functions you know (almost) all about working with arrows.
> When generalizing a pure algorithm, something like "f3 . f2 . f1",
> or in Unix pipe style "f1>>> f2>>> f3", you don't have to rewrite
> the code, you just generalize function composition.
Yes, but the >=> operator lets you do the same thing with monads, and in
fact I use it all the time to do point-free programming with monads, so
this isn't at all an advantage that arrows have over monads.
> When constructing code, it is of course sometimes simpler to start with a
> point wise version and then refactor and rewrite it into a more compact point
> free version. The problem with arrows seems, that the arrow style forces to
> start with the point free style. And that may be the main hurdle in mind.
No, that is not at all the problem with arrows. The problem with arrows
is that they are more restrictive than monads in two respects. First,
unlike monads, in general they do not let you perform an arbitrary
action in response to an input. Second, they place restrictions on how
you define the input arguments of the arrow because you can't feed the
output of one arrow into to input of the next unless said input is
captured in the arrows type.
To be more concrete about my second point, suppose you have some monadic
f :: a -> b -> m c
How would you structure this same action as an arrow? One thing that
you could do is take one of the arguments and turn it into the input of
f' :: a -> Arrow b c
But now you can't feed the output of an arrow into the first argument.
Alternatively, you could pack both arguments into the input of the arrow:
f'' :: Arrow (a,b) c
Great, but now you have made it more awkward to use f'' because you have
to always pack the arguments into a tuple, so that for example if one of
the arguments is a constant then you can no longer easily use currying.
The advantage of f over both alternatives is that you don't have to
waste any of your time fitting multiple input arguments into the input
type of an arrow.
In fact, if the first argument to f'' is usually a constant, then f'' is
arguably more awkward to use in a point-free setting than f, because
instead of being able to write
a >=> f 42 >=> b
You have to write something like
a >>> (const 42 &&& id) >>> f'' >>> b
Of course, if the first argument were *always* a constant then you could
use f', but then you lose the ability to ever feed in the output of an
arrow into the first argument. So in short, arrows force you to make
choices and trade-offs that never come up when using monads.
In conclusion, while I greatly appreciate you taking the time to explain
your reasoning, it still looks to me like there is nothing you have
gained by using arrows except adding extra unnecessary complexity in
More information about the Haskell-Cafe