Sequence of lifting transformation operators

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
5 messages Options
Reply | Threaded
Open this post in threaded view
|

Sequence of lifting transformation operators

Tyson Whitehead
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.
_______________________________________________
Haskell-Cafe mailing list
To (un)subscribe, modify options or view archives go to:
http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe
Only members subscribed via the mailman list are allowed to post.
Reply | Threaded
Open this post in threaded view
|

Re: Sequence of lifting transformation operators

Erik de Castro Lopo-34
Tyson Whitehead wrote:

> <$$> :: (a -> b -> c) -> f a -> f b -> f c

I'd just like to point out that this operator is often used by
as the oeprator for fmap2:


  (<$$>) :: (Functor f1, Functor f) => (a -> b) -> f (f1 a) -> f (f1 b)
  (<$$>) = fmap . fmap

Erik
--
----------------------------------------------------------------------
Erik de Castro Lopo
http://www.mega-nerd.com/
_______________________________________________
Haskell-Cafe mailing list
To (un)subscribe, modify options or view archives go to:
http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe
Only members subscribed via the mailman list are allowed to post.
Reply | Threaded
Open this post in threaded view
|

Re: Sequence of lifting transformation operators

Taeer Bar-Yam
This is (IMO) very similar in use-case to Idris' bang-notation. I'll give a brief
summary of what that is and then explain the pros/cons that I see between them.

In Idris the do notation has the added notation that
do return $ !a + !b
would desugar to
do
  a' <- a
  b' <- b
  return $ a' + b'

So !a unwraps a higher up and then uses the unwrapped version.
Thus if you want to apply a function to apply a function to some wrapped and
some unwrapped values:
do return $ f !a b !c !d


Pros/Cons:
- Idris notation is (IMO) more visually appealing.
  - In particular, it puts the information about which arguments are lifted next
    to the arguments themselves, which matches our intuition about what's going on
- While it matches our intuition, it does *not* match what's actually going on,
  so that's a con.
- Idris notation can lift things more than once:
  do return $ f !!a !b !!!!c
- Idris notation is syntactic sugar, not a first-class operator
  - So that means no currying, no passing it in as an argument, etc. (though
    with lambdas this is not as bad as it otherwise would be)
- Idris notation is for monads, so it would not work for things that are
  applicative but not monads (though I'm not entirely sure what falls into this
  category)

What do you y'all think? Do they operate in different enough spaces that they
should both exist (like applicatives and moands), or is one clearly better?

  --Taeer
_______________________________________________
Haskell-Cafe mailing list
To (un)subscribe, modify options or view archives go to:
http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe
Only members subscribed via the mailman list are allowed to post.
Reply | Threaded
Open this post in threaded view
|

Re: Sequence of lifting transformation operators

Alexey Vagarenko
What is the order of unwrapping?
`return $ !a + !b` doesn't equals `return $ !b + !a` right?

2017-01-31 9:37 GMT+05:00 Taeer Bar-Yam <[hidden email]>:
This is (IMO) very similar in use-case to Idris' bang-notation. I'll give a brief
summary of what that is and then explain the pros/cons that I see between them.

In Idris the do notation has the added notation that
do return $ !a + !b
would desugar to
do
 a' <- a
 b' <- b
 return $ a' + b'

So !a unwraps a higher up and then uses the unwrapped version.
Thus if you want to apply a function to apply a function to some wrapped and
some unwrapped values:
do return $ f !a b !c !d


Pros/Cons:
- Idris notation is (IMO) more visually appealing.
 - In particular, it puts the information about which arguments are lifted next
   to the arguments themselves, which matches our intuition about what's going on
- While it matches our intuition, it does *not* match what's actually going on,
 so that's a con.
- Idris notation can lift things more than once:
 do return $ f !!a !b !!!!c
- Idris notation is syntactic sugar, not a first-class operator
 - So that means no currying, no passing it in as an argument, etc. (though
   with lambdas this is not as bad as it otherwise would be)
- Idris notation is for monads, so it would not work for things that are
 applicative but not monads (though I'm not entirely sure what falls into this
 category)

What do you y'all think? Do they operate in different enough spaces that they
should both exist (like applicatives and moands), or is one clearly better?

 --Taeer

_______________________________________________
Haskell-Cafe mailing list
To (un)subscribe, modify options or view archives go to:
http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe
Only members subscribed via the mailman list are allowed to post.


_______________________________________________
Haskell-Cafe mailing list
To (un)subscribe, modify options or view archives go to:
http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe
Only members subscribed via the mailman list are allowed to post.
Reply | Threaded
Open this post in threaded view
|

Re: Sequence of lifting transformation operators

Taeer Bar-Yam
In general no. IMO this is better used with commutative monads (is that the
right term?) such as [] or Maybe, rather than monads such as IO.

However, there is a well-defined order, that I presume is inner-to-outer
left-to-right, but I don't actually have experience programming in Idris.

Reference: http://docs.idris-lang.org/en/latest/tutorial/interfaces.html#notation

Excerpts from Alexey Vagarenko's message of January 31, 2017 12:56 am:
> What is the order of unwrapping?
> `return $ !a + !b` doesn't equals `return $ !b + !a` right?

  --Taeer
_______________________________________________
Haskell-Cafe mailing list
To (un)subscribe, modify options or view archives go to:
http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe
Only members subscribed via the mailman list are allowed to post.