Here is an idea for some more function composition operators, beyond just (.):
(f .$ g) x = (f) . (g $ x) (f $. g) x = (f $ x) . (g) (f .$$ g) x y = (f) . (g $ x $ y) (f $.$ g) x y = (f $ x) . (g $ y) (f $$. g) x y = (f $ x $ y) . (g) -- etc. infixl 8 .$, $., .$$, $.$, $$. -- slightly less tight than (.)
The .$ name is supposed suggests that an extra argument is applied on the right before the functions are composed. Notice also that the dollars and dot on the left hand site match those on the right hand side. These combinators make writing point free code easier:
concatMap = concat .$ map sum23 = (+) . (2*) $. (3*) -- \x y -> 2*x + 3*y
Here is another family of composition operators:
(f $. g) x = (f) (g x) -- a.k.a. (.) (f .$ g) x = (f x) (g) -- a.k.a. flip (f $.. g) x y = (f) (g x y) (f .$. g) x y = (f x) (g y) (f ..$ g) x y = (f x y) (g) (f $... g) x y z = (f) (g x y z) (f .$.. g) x y z = (f x) (g y z) (f ..$. g) x y z = (f x y) (g z) (f ...$ g) x y z = (f x y z) (g) -- etc. infixl 8 $., .$, $..,.$.,..$, $...,.$..,..$.,...$
Think of the . as the placeholder for an argument. It would be better if I could use _, but Haskell doesn't allow that. You can also think of the dots as the points from point-free style, so these operators allow for the preservation of the number of points :). With these operators the previous example becomes:
concatMap = concat $.. map sum23 = (+) $. (2*) .$. (3*) -- \x y -> 2*x + 3*y
I like the second family better, because they do not use (.), which makes the first family more confusing. What do you think? Would these operators be useful in practice?
Comments
I like the second family of operators better too, but all in all it is too much of a good thing and I really won't end up using any of them... ok, I sometimes wish to have (.) and (.) but still I'm not sure I would use them if available. The source doesn't seem to be more readable that way. Too much of mental parsing before understanding a simple line
e.g.
is much easier to read and more natural then
Another one I like to have:
() :: (Functor f) => (a -> b) -> (c -> f a) -> c -> f b f g = (f ) . g -- f is pure and g is an Applicative or Monad
So one can beautifully combine applicatives/monads with pure function:
uhm.... your blog did eat up some symbols. Hope it works now:
As the SKI (or BKCW) calculus shows, for real combinatory / compositional function construction, we'd like to be able to duplicate and / or reorder arguments, as well as simply slinging them around. Does your notation scheme have any natural place for the S or W combinator?
(Now you've got me imagining a visual DSL for creating combinators! I made a very clumsy stab at it a while ago at http://www.perlmonks.org/?node_id=809842.)
Hi Twan
(f $.. g) x y = (f) (g x y) is "blackbird"
(f $... g) x y z = (f) (g x y z) is "bunting"
I sometimes use these two in Haskell as `oo` and `ooo` parodying ML's composition operator o.
(f .$. g) x y = (f x) (g y) is "dove"
(f ..$. g) x y z = (f x y) (g z) is "dickcissel"
(f .$.. g) x y z = (f x) (g y z) is "eagle"
Generally I don't think such combinators are useful in practice for Haskell. Historically Haskell has got by with a fairly meagre set of combinators, and people are habitual in what they use. Adding extra ones, especially with infix operators, seems like a local dialect - fine for personal code and golf, unwise for open-source libraries.
Of course, if the combinators had been part of the Prelude from the beginning it would be a different matter.
You might want to check out http://hackage.haskell.org/packages/archive/not-in-base/0.1.1/doc/html/NIB-Pointfree.html.
The syntax is nearly identical :)
I've seen somewhere in LiveJournal an operator
that is somehow rarely seen in literature. It has a magnificent property that
etc. For example
Reply