[Haskell-cafe] Gluing pipes
matt at immute.net
Wed Dec 3 13:17:59 EST 2008
>From time to time, I've wanted to have a more pleasant way of writing
point-free compositions of curried functions. One might want to
transform both the first and second arguments, for instance, or only
the third argument, of a curried function. I've never known a
(non-cryptic) way to do this.
For example, given:
f :: a -> b -> c
g :: a1 -> a
h :: b2 -> b
I'd like to be able to write something like:
\ x y -> f (g x) (h y)
in a way that is both point-free and applicative. In other words, I'd
like to apply a function to "pipes" or transformers rather than to
Recent posts by Conal Elliott [1,2] got me thinking about this again,
and I've found a simple solution.
I use two of Conal's combinators:
argument = flip (.)
result = (.)
And now we define:
infixr 2 ~>
f ~> g = argument f . result g
infixl 1 $.
($.) = flip ($)
Which lets us write:
-- transform both arguments
f $. g ~> h ~> id
-- transform just the second argument
f $. id ~> h ~> id
The name ($.) is chosen to indicate that this is (roughly) a
composition disguised as an application. The transformer spec to the
right of ($.) looks like the type of the function to the left, and
consists of a transformer for each argument and one for the result
type. Of course, (~>) is right associative, and id can match the
entire tail "in bulk", so we can also write something like:
f $. g ~> id
And of course, each transformer can be a pipeline, so assuming proper
types, we can do things like:
f $. id ~> (length.snd.unWrap) ~> wrap
More details here:
1. Is there already another well-known way to do this? It seems a
common enough problem...
2. Do these particular combinators already exist somewhere with other names?
3. Are there better names for these functions?
More information about the Haskell-Cafe