More composition operators

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

anonymousx

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.

sum23 x y = 2*x + 3*y

is much easier to read and more natural then

sum23 = (+) $. (2*) .$. (3*)

Another one I like to have:

infix 1 

() :: (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:

concatMapM f = concat  mapM f
anonymousx

uhm.... your blog did eat up some symbols. Hope it works now:

f <.> g = (f <$>) . g
Jade NBx

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.)

Stephen Tetleyx

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.

Oscarx

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 :)

Philip PolkovnikovDate: 2016-03-17T21:24Zx

I've seen somewhere in LiveJournal an operator

infixr ? ~>
(f ~> g) h = g . h . f

that is somehow rarely seen in literature. It has a magnificent property that

(f ~> g ~> h) k x y = h (k (f x) (g y))

etc. For example

(f .$ g) x = (f) . (g $ x) = (id ~> ($ x) ~> id) (.) f g
(f $. g) x = (f $ x) . (g) = (($ x) ~> id ~> id) (.) f g
(f $.. g) x y = (f) (g x y) = (id ~> id ~> f) g x y
(f .$. g) x y = (f x) (g y) = (id ~> g ~> id) f x y
(f $... g) x y z = (f) (g x y z) = (id ~> id ~> id ~> f) g x y z

Reply

(optional)
(optional, will not be revealed)
Name of the lazy functional programming language I write about:
Use > code for code blocks, @code@ for inline code. Some html is also allowed.