avoiding parens in postfix applicative notation

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

avoiding parens in postfix applicative notation

Johannes Waldmann-2
Dear Cafe -

operators <$> and <*> have their precedence
so that this (silly example) works without parens:

  (,) <$> "foo" <*> "bar"

Most of the time, I find that the function
(the first argument) is the largest sub-expression,
so I want to put it last. I can do this

  import Control.Lens.Lens ((<&>))

  "foo" <**> ( "bar" <&> (,) )

but (even ignoring that this pulls in a library
with a ton of dependencies) this needs parens,
and I find this quite ugly when the closing parenthesis
comes at the end of lambda expression
that spans several lines.

One work-around is

  ( "foo" <**> ) $ "bar" <&> (,)

Can this be done in a less noisy way?

- J.W.


PS: Bike-sheddingly, shouldn't this (<&>)
be defined right next to (<$>) ?
There's nothing that would tie it to lenses?
And, (&) right next to ($) ?
_______________________________________________
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: avoiding parens in postfix applicative notation

MarLinn

> operators <$> and <*> have their precedence so that this (silly example) works without parens:
>
>    (,) <$> "foo" <*> "bar"
>
> Most of the time, I find that the function (the first argument) is the largest sub-expression, so I want to put it last. I can do this
>
>    import Control.Lens.Lens ((<&>))
>
>    "foo" <**> ( "bar" <&> (,) )
>
> but (even ignoring that this pulls in a library with a ton of dependencies) this needs parens, and I find this quite ugly when the closing parenthesis comes at the end of lambda expression that spans several lines.

Hello,

what's bad about the dead simple solution?

     foobar = makeTuple <$> "foo" <*> "bar"
       where
         makeTuple = (,) -- bonus: name as documentation

But if you insist: (,) <$> "foo" <*> "bar" is the same as (<*> "bar") .
(<$> "foo") $ (,). But that would flip the order of the arguments. So
maybe flip them back:

     import Control.Category ( (>>>) )

     foobar = (<$> "foo") >>> (<*> "bar")  $  (,)

Now let's extract new functions:

     a  >>>* b =      a  >>> (<*> b) ; infixl 4  >>>*
     a $>>>* b = (<$> a) >>>*     b  ; infixl 4 $>>>*


     foobar = "foo" $>>>* "bar" >>>* "baz"  $  (,,)

You might want to bike-shed these names a bit, but that sounds like the
operators you want. Maybe name them (>$) and (>*)?

Side note: sometimes if the function is very short I feel like using
such extra operators for "infix" applicatives as well:

     comma = "foo" <*< (,) >*> "bar" -- same as(,) <$> "foo" <*> "bar"

But I'm still not sure if that's a good idea. I've been bitten multiple
times because of my own invented operators. What was (>>?!) again? Or
(^>>>&)? The more I use Haskell the more I tend to solutions like that
first dead-simple one.

Cheers,
MarLinn

_______________________________________________
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: avoiding parens in postfix applicative notation

Neil Mayhew
On 2018-02-06 07:59 AM, MarLinn wrote:
> I've been bitten multiple times because of my own invented operators.
> What was (>>?!) again? Or (^>>>&)? The more I use Haskell the more I
> tend to solutions like that first dead-simple one.

I agree.

Also, since

func <$> "foo" <*> "bar"

is the lifted equivalent of

func "foo" "bar"

I find it unintuitive to read or write the logic in the opposite order.

Whether we like it or not, Haskell is fundamentally a right-to-left
language. Or, to look at it another way, top-down corresponds to
left-to-right, and bottom-up corresponds to right-to-left. Perhaps it
depends on whether you're a top-down thinker (like me) or a bottom-up
thinker. I much prefer `where` to `let`, for example.
_______________________________________________
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: avoiding parens in postfix applicative notation

Jason Shipman
Hi Johannes,

The lens library defines (<&>) with very low precedence (1), whereas (<$>) has precedence 4.  If you define (<&>) yourself and specify a precedence higher than 4, or just don’t specify a precedence at all, your example will work fine:

(<&>) :: Functor f => f a -> (a -> b) -> f b
(<&>) = flip fmap

"foo" <**> "bar" <&> (,)

You can do hanging style too, with no dollar sign:

"foo" <**> "bar" <&> \q r ->
..(q, r)

If you don’t like defining ad-hoc versions of things like (<&>), you might find the ‘overhang’ library useful: https://hackage.haskell.org/package/overhang-1.0.0/docs/Overhang.html#v:onMap

The overhang equivalent of (<&>) is ‘onMap’ and it can be used in the same way:

import Overhang (onMap)

"foo" <**> "bar" `onMap` (,)

The code aesthetics around writing a “final" lambda that spans several lines was the driver for creating that library!

Jason

On Feb 6, 2018, at 12:37 PM, Neil Mayhew <[hidden email]> wrote:

On 2018-02-06 07:59 AM, MarLinn wrote:
I've been bitten multiple times because of my own invented operators. What was (>>?!) again? Or (^>>>&)? The more I use Haskell the more I tend to solutions like that first dead-simple one.

I agree.

Also, since

func <$> "foo" <*> "bar"

is the lifted equivalent of

func "foo" "bar"

I find it unintuitive to read or write the logic in the opposite order.

Whether we like it or not, Haskell is fundamentally a right-to-left language. Or, to look at it another way, top-down corresponds to left-to-right, and bottom-up corresponds to right-to-left. Perhaps it depends on whether you're a top-down thinker (like me) or a bottom-up thinker. I much prefer `where` to `let`, for example.
_______________________________________________
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: avoiding parens in postfix applicative notation

Johannes Waldmann-2
In reply to this post by Johannes Waldmann-2
Thanks for comments and suggestions.


> The lens library defines (<&>) with very low precedence

Yes. I guess my question was: Why?


> f <$> foo <*> bar where f x y = ...

I avoid "where" because

* it uses an identifier before it is defined

* it is not as composable as "let", which is an
  expression, but "where" can only be attached to
  declarations - I can write  1 + let x = 3 in x
  but not  1 + ( x where x = 3 )

- J.W.
_______________________________________________
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: avoiding parens in postfix applicative notation

Johannes Waldmann-2
In reply to this post by Johannes Waldmann-2
for reference, previous discussion at
https://mail.haskell.org/pipermail/libraries/2017-February/027685.html
On whether to put <&> in Data.Functor. Will this happen?
- J.W.
_______________________________________________
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.