avoiding parens in postfix applicative notation

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 ($) ?

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

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.

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:onMa... https://hackage.haskell.org/package/overhang-1.0.0/docs/Overhang.html#v:onMa... 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
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.
participants (4)
-
Jason Shipman
-
Johannes Waldmann
-
MarLinn
-
Neil Mayhew