# [Haskell-cafe] Sequence of lifting transformation operators

Fri Jan 27 20:39:52 UTC 2017

```A couple of times I find myself wishing for an easy way to transform a
function by picking and choosing which of its operators are lifted.
For example, consider

f <\$> x1 <*> pure x2 <*> x3 <*> pure x4

we can put all the details of this into f itself

f' x1 x2 x3 x4 = f <\$> x1 <*> pure x2 <*> x3 <*> pure x4

and then just write

f' x1 x2 x3 x4

I think it might be nice to have a series of transformation functions
that made this easy to write.  Something like a series of operator
like so

f' = f <\$_\$_>

where it would be read that f' is a lifted f such that the first
argument is lifted, the second is not, the third is, and the fourth is
not (this is consistent with f <\$> returning a being a lifted f with
first argument being lifted).

This would make code such as the following

flip (go finalX finalY) y `liftM` mx

= go <__\$_> finalX finalY mx y

much more robust to write (how it gets written now depends very much
on the number of arguments, their order, which ones are lifted, etc.),
a whole lot easier to read, and don't even get me started on the
points free use (go <__\$_>)!

A library could easily provide the first six or so variants (2^6 = 64
functions).  If they were really useful the compiler could provide the
rest.

<\$> :: (a -> b) -> f a -> f b
<\$\$> :: (a -> b -> c) -> f a -> f b -> f c
<\$_> :: (a -> b -> c) -> f a -> b -> f c
<_\$> :: (a -> b -> c) -> a -> f b -> f c
...

Cheers!  -Tyson

PS:  It would be nice to also have ones that work with f being lifted.
That is like how we have <\$> for an unlifted f and <*> for a lifted f.

<*> :: f (a -> b) -> f a -> f b
<**> :: f (a -> b -> c) -> f a -> f b -> f c
<*_> :: f (a -> b -> c) -> f a -> b -> f c
<_*> :: f (a -> b -> c) -> a -> f b -> f c
...

A bit of a pain here is that <**> is actually already taken as <*>
with reversed arguments.  Possibly this would call for something like

<\$^> :: (a -> b) -> f a -> f b
<\$^^> :: (a -> b -> c) -> f a -> f b -> f c
<\$^_> :: (a -> b -> c) -> f a -> b -> f c
<\$_^> :: (a -> b -> c) -> a -> f b -> f c
...

and

<*^> :: f (a -> b) -> f a -> f b
<*^^> :: f (a -> b -> c) -> f a -> f b -> f c
<*^_> :: f (a -> b -> c) -> f a -> b -> f c
<*_^> :: f (a -> b -> c) -> a -> f b -> f c
...

where they are prefixed by \$ or * to indicate what type f is and then
_ encodes an unlifted argument position and ^ a lifted argument
position.
```