[Haskell-cafe] Sequence of lifting transformation operators
Tyson Whitehead
twhitehead at gmail.com
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
https://github.com/snoyberg/conduit/blob/be803218b5b2acaad2eb720ca3a27a4d0734fba8/conduit/Data/Conduit/Internal/Conduit.hs#L543
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
this instead
<$^> :: (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.
More information about the Haskell-Cafe
mailing list