
Hello, I would like to propose adding a flipped variant of <$> to Data.Functor: (<$$>) ∷ Functor f ⇒ f α → (α → β) → f β (<$$>) = flip (<$>) Please see the ticket for motivation and patch: http://hackage.haskell.org/trac/ghc/ticket/3962 Discussion period: 2 weeks. regards, Bas

On Wed, Apr 7, 2010 at 11:13 AM, Bas van Dijk
Hello,
I would like to propose adding a flipped variant of <$> to Data.Functor:
(<$$>) ∷ Functor f ⇒ f α → (α → β) → f β (<$$>) = flip (<$>)
Please see the ticket for motivation and patch:
http://hackage.haskell.org/trac/ghc/ticket/3962
Discussion period: 2 weeks.
I added a reply to the ticket just before you sent this email. :) Cheers, Johan

On Wed, Apr 7, 2010 at 11:28 AM, Johan Tibell
I added a reply to the ticket just before you sent this email. :)
Johan, thanks for your reply. Let me quote it:
I'm not in favor of this proposal. Naming trivial compositions puts a complexity tax on all users of the library...
Note that I'm proposing to export <$$> from Data.Functor not from the Prelude. So the complexity tax is localized for users of that module only.
...and we end up with 2*n operators instead of n operators and one flip function. It's trivial to define the function locally or in a helper module.
In a way I already see modules like Control.Monad, Control.Applicative, Control.Arrow, Data.Functor, etc. has "helper" modules defining trivial compositions of the primitive methods.
To elaborate: At work some of our core APIs have gotten dramatically more complex due to their maintainers allowing people, in interest to keep their own code cleaner, to add small helper functions to those APIs. This is now recognized as bad practice and discouraged with a call to "not fear the semicolon"! (We use mostly imperative languages at work.)
In Haskell this will probably be called: "not fear the dot!" :-) Of course that problem can also be solved by exporting these trivial compositions from a different module from which the primitives are exported. However some of these trivial compositions are so useful that users tend to always include both the primitive module and the helper module, thereby defeating the purpose of the split modules a bit. I'm more in favor of exporting both the primitive and the trivial compositions from the same module provided there's good documentation with clear sectioning available. regards, Bas

Hi Bas,
On Wed, Apr 7, 2010 at 2:11 PM, Bas van Dijk
Of course that problem can also be solved by exporting these trivial compositions from a different module from which the primitives are exported. However some of these trivial compositions are so useful that users tend to always include both the primitive module and the helper module, thereby defeating the purpose of the split modules a bit.
Adding more modules also add more complexity.
I'm more in favor of exporting both the primitive and the trivial compositions from the same module provided there's good documentation with clear sectioning available.
While documentation certainly helps it doesn't solve the whole problem. The API is still bigger, there are more things to read and understand. More operators also make user code harder to understand and I think we should only use operators (and only a minimal amount of them) for very fundamental operations (like arithmetic). Functors are fundamental to they deserve an operator for fmap, <$>, as learning what it means pays off in the long run if it's used frequently. If an operator would only be used infrequently it's a good argument for using a more descriptive function name instead of an operator. -- Johan

On Wed, Apr 7, 2010 at 9:42 AM, Johan Tibell
Hi Bas,
On Wed, Apr 7, 2010 at 2:11 PM, Bas van Dijk
wrote: Of course that problem can also be solved by exporting these trivial compositions from a different module from which the primitives are exported. However some of these trivial compositions are so useful that users tend to always include both the primitive module and the helper module, thereby defeating the purpose of the split modules a bit.
Adding more modules also add more complexity.
I would argue that adding one function to a module that only exports a single method that is already available through Control.Applicative is hardly breaking its complexity budget. ;)
While documentation certainly helps it doesn't solve the whole problem. The API is still bigger, there are more things to read and understand. More operators also make user code harder to understand and I think we should only use operators (and only a minimal amount of them) for very fundamental operations (like arithmetic). Functors are fundamental to they deserve an operator for fmap, <$>, as learning what it means pays off in the long run if it's used frequently. If an operator would only be used infrequently it's a good argument for using a more descriptive function name instead of an operator.
I'm more surprised that this combinator of this sort is NOT already present and since the applicative equivalent is present in Control.Applicative explaining away its absence is harder than justifying its inclusion. +1 from me. -Edward Kmett

On Wed, Apr 07, 2010 at 03:42:48PM +0200, Johan Tibell wrote:
If an operator would only be used infrequently it's a good argument for using a more descriptive function name instead of an operator.
IMHO this is your best argument against the inclusion of <$$>. Indeed, while many haskellers are familiar with <$>, how many are familiar with <$ ? -- Felipe.

On Wed, 7 Apr 2010 11:13:02 +0200, Bas van Dijk
Hello,
I would like to propose adding a flipped variant of <$> to Data.Functor:
(<$$>) ∷ Functor f ⇒ f α → (α → β) → f β (<$$>) = flip (<$>)
Please see the ticket for motivation and patch:
I support this proposition, in particular the name choice which is consistent. -- Nicolas Pouillard http://nicolaspouillard.fr

On Wed, Apr 7, 2010 at 11:13 AM, Bas van Dijk
I would like to propose adding a flipped variant of <$> to Data.Functor:
(<$$>) ∷ Functor f ⇒ f α → (α → β) → f β (<$$>) = flip (<$>)
It is worth doing some simple statistics: There are 5939 hackage packages in my git-repo archive. Of these, there are 10 apps which import Data.Functor directly. The number for Control.Applicative is 418. 'flip\s*<$>' is defined by 6 different packages: jlouis@jlouis-desktop:~/Projects/hackage$ git grep 'flip\s\+<\$>' | sed -e 's/:.*$//' HXQ-0.18.2.tar.gz.dir/HXQ-0.18.2/src/hxml-0.2/LLParsing.hs HXQ-0.18.2.tar.gz.dir/HXQ-0.18.2/src/hxml-0.2/LLParsing.hs action-permutations-0.0.0.0.tar.gz.dir/action-permutations-0.0.0.0/Control/Applicative/Permutation.hs curry-frontend-0.2.9.tar.gz.dir/curry-frontend-0.2.9/src/Curry/Syntax/LLParseComb.lhs curry-frontend-0.2.9.tar.gz.dir/curry-frontend-0.2.9/src/Curry/Syntax/LLParseComb.lhs ideas-0.5.8.tar.gz.dir/ideas-0.5.8/src/Text/Parsing.hs uu-parsinglib-2.3.1.tar.gz.dir/uu-parsinglib-2.3.1/src/Text/ParserCombinators/UU/Derived.hs uu-parsinglib-2.3.1.tar.gz.dir/uu-parsinglib-2.3.1/src/Text/ParserCombinators/UU/Derived.hs uu-parsinglib-2.3.1.tar.gz.dir/uu-parsinglib-2.3.1/src/Text/ParserCombinators/UU/Derived.hs uu-parsinglib-2.3.1.tar.gz.dir/uu-parsinglib-2.3.1/src/Text/ParserCombinators/UU/Derived.hs uulib-0.9.12.tar.gz.dir/uulib-0.9.12/src/UU/Parsing/Derived.hs uulib-0.9.12.tar.gz.dir/uulib-0.9.12/src/UU/Parsing/Derived.hs uulib-0.9.12.tar.gz.dir/uulib-0.9.12/src/UU/Parsing/Derived.hs uulib-0.9.12.tar.gz.dir/uulib-0.9.12/src/UU/Parsing/Derived.hs The confounder is: How many packages would have used the flipped variant had they had access to it. Personally, I wouldn't add it, but it cannot hurt since only 10 hackage packages would potentially be affected by the change. For non-hackage packages, if the hackage packages are taken as a sample, we have 0.1% of the packages affected (fewer, actually). -- J.

What about if you add grep 'flip fmap' ? -Edward Kmett On Wed, Apr 7, 2010 at 8:34 AM, Jesper Louis Andersen < jesper.louis.andersen@gmail.com> wrote:
On Wed, Apr 7, 2010 at 11:13 AM, Bas van Dijk
wrote: I would like to propose adding a flipped variant of <$> to Data.Functor:
(<$$>) ∷ Functor f ⇒ f α → (α → β) → f β (<$$>) = flip (<$>)
It is worth doing some simple statistics: There are 5939 hackage packages in my git-repo archive. Of these, there are 10 apps which import Data.Functor directly. The number for Control.Applicative is 418. 'flip\s*<$>' is defined by 6 different packages:
jlouis@jlouis-desktop:~/Projects/hackage$ git grep 'flip\s\+<\$>' | sed -e 's/:.*$//' HXQ-0.18.2.tar.gz.dir/HXQ-0.18.2/src/hxml-0.2/LLParsing.hs HXQ-0.18.2.tar.gz.dir/HXQ-0.18.2/src/hxml-0.2/LLParsing.hs
action-permutations-0.0.0.0.tar.gz.dir/action-permutations-0.0.0.0/Control/Applicative/Permutation.hs
curry-frontend-0.2.9.tar.gz.dir/curry-frontend-0.2.9/src/Curry/Syntax/LLParseComb.lhs
curry-frontend-0.2.9.tar.gz.dir/curry-frontend-0.2.9/src/Curry/Syntax/LLParseComb.lhs ideas-0.5.8.tar.gz.dir/ideas-0.5.8/src/Text/Parsing.hs
uu-parsinglib-2.3.1.tar.gz.dir/uu-parsinglib-2.3.1/src/Text/ParserCombinators/UU/Derived.hs
uu-parsinglib-2.3.1.tar.gz.dir/uu-parsinglib-2.3.1/src/Text/ParserCombinators/UU/Derived.hs
uu-parsinglib-2.3.1.tar.gz.dir/uu-parsinglib-2.3.1/src/Text/ParserCombinators/UU/Derived.hs
uu-parsinglib-2.3.1.tar.gz.dir/uu-parsinglib-2.3.1/src/Text/ParserCombinators/UU/Derived.hs uulib-0.9.12.tar.gz.dir/uulib-0.9.12/src/UU/Parsing/Derived.hs uulib-0.9.12.tar.gz.dir/uulib-0.9.12/src/UU/Parsing/Derived.hs uulib-0.9.12.tar.gz.dir/uulib-0.9.12/src/UU/Parsing/Derived.hs uulib-0.9.12.tar.gz.dir/uulib-0.9.12/src/UU/Parsing/Derived.hs
The confounder is: How many packages would have used the flipped variant had they had access to it. Personally, I wouldn't add it, but it cannot hurt since only 10 hackage packages would potentially be affected by the change. For non-hackage packages, if the hackage packages are taken as a sample, we have 0.1% of the packages affected (fewer, actually).
-- J. _______________________________________________ Libraries mailing list Libraries@haskell.org http://www.haskell.org/mailman/listinfo/libraries

On Wed, Apr 7, 2010 at 3:09 PM, Edward Kmett
What about if you add grep 'flip fmap' ?
jlouis@jlouis-desktop:~/Projects/hackage$ git grep 'flip\s\+fmap' | sed -e 's/\(.*\)\.tar.gz.*/\1/' | sort | uniq | wc -l 26 It doesn't change much with 26 packages on top of the 10. I'm with Johan here. Don't add it. -- J.

Hi Felipe,
On Wed, Apr 7, 2010 at 3:09 PM, Felipe Lessa
On Wed, Apr 07, 2010 at 11:13:02AM +0200, Bas van Dijk wrote:
I would like to propose adding a flipped variant of <$> to Data.Functor:
(<$$>) ∷ Functor f ⇒ f α → (α → β) → f β (<$$>) = flip (<$>)
+1
I've needed <$$> many times and had to use 'flip fmap' instead.
In my opinion this is not a good criteria for including a function. For any function composition you can find a subset of the community that uses that particular composition. Yet, if we add all the function compositions that some group of people use in their code our APIs get much more complicated. To make matters worse, the incentives for arguing for and against any particular addition are somewhat perverse: The people who use the particular composition think it's a great idea, they can make their own code a bit more beautiful. The people who don't use it would perhaps prefer to not see it added but it's time consuming to argue against every single proposal and the benefit to get any particular proposal rejected is small. This is how many APIs at [work] got more complicated. Someone argues very strongly that they need this particular addition and the maintainer gets many addition proposals. Eventually he/she gives in. After some time someone rewrites the library from scratch as it's to hard to understand anymore. -- Johan

On Wed, Apr 07, 2010 at 03:33:51PM +0200, Johan Tibell wrote:
Hi Felipe,
Hello! :)
On Wed, Apr 7, 2010 at 3:09 PM, Felipe Lessa
wrote: I've needed <$$> many times and had to use 'flip fmap' instead.
In my opinion this is not a good criteria for including a function. [snip]
I think I understand your point very well. I'm also not fond of adding shortcuts, and that's why I said I used 'flip fmap' while I could have defined <$$> myself instead. My reasons for adding this particular function are: 1) <$> is very useful because it is infix, while `fmap` is ugly and doesn't have a nice fixity. -- Prelude> :t \f g x -> f . g `fmap` x <interactive>:1:10: Precedence parsing error cannot mix `.' [infixr 9] and `fmap' [infixl 9] in the same infix expression -- Prelude Control.Applicative> :t \f g x -> f . g <$> x \f g x -> f . g <$> x :: (Functor f) => (b -> c) -> (a -> b) -> f a -> f c -- <$$> will be as concise and useful as <$>, maybe even more, because `flip fmap` isn't valid. 2) Simmetry, as the ticket says.
Yet, if we add all the function compositions that some group of people use in their code our APIs get much more complicated.
I completely agree, but I think you're overreacting to this proposal (no offense intended, please :]). I don't see a tendency of adding every combinator to the libraries, and I don't think this proposal will change anything. Cheers, -- Felipe.

On Wed, Apr 7, 2010 at 3:58 PM, Felipe Lessa
Simmetry, as the ticket says.
Indeed, I would like to emphasize that my main reason for adding a flipped fmap is symmetry. I find it hard to explain why <$$> shouldn't be in this list: (<$>) ∷ Functor f ⇒ (α → β) → (f α → f β) (<$$>) ∷ Functor f ⇒ f α → (α → β) → f β (<*>) ∷ Applicative f ⇒ f (α → β) → (f α → f β) (<**>) ∷ Applicative f ⇒ f α → f (α → β) → f β (>>=) ∷ Monad f ⇒ f α → (α → f β) → f β (=<<) ∷ Monad f ⇒ (α → f β) → (f α → f β) Thanks for the excellent discussion so far, Bas

On Wed, Apr 7, 2010 at 4:12 PM, Bas van Dijk
On Wed, Apr 7, 2010 at 3:58 PM, Felipe Lessa
wrote: Simmetry, as the ticket says.
Indeed, I would like to emphasize that my main reason for adding a flipped fmap is symmetry. I find it hard to explain why <$$> shouldn't be in this list:
(<$>) ∷ Functor f ⇒ (α → β) → (f α → f β) (<$$>) ∷ Functor f ⇒ f α → (α → β) → f β
(<*>) ∷ Applicative f ⇒ f (α → β) → (f α → f β) (<**>) ∷ Applicative f ⇒ f α → f (α → β) → f β
(>>=) ∷ Monad f ⇒ f α → (α → f β) → f β (=<<) ∷ Monad f ⇒ (α → f β) → (f α → f β)
I think the argument I would make is that (<**>) and (=<<) shouldn't have been added in the first place. Now, it might not be feasible to remove them but should we really add flipped versions of everything because these exists. I understand the Functor feels "close" to Applicative and Monad somehow but you could make the argument that any non-commutative operator should now have a flipped versions and there are more operators than those you listed above.
Thanks for the excellent discussion so far,
Thank you! -- Johan

Johan Tibell wrote:
Bas van Dijk wrote:
Indeed, I would like to emphasize that my main reason for adding a flipped fmap is symmetry. I find it hard to explain why <$$> shouldn't be in this list:
(<$>) ∷ Functor f ⇒ (α → β) → (f α → f β) (<$$>) ∷ Functor f ⇒ f α → (α → β) → f β
(<*>) ∷ Applicative f ⇒ f (α → β) → (f α → f β) (<**>) ∷ Applicative f ⇒ f α → f (α → β) → f β
(>>=) ∷ Monad f ⇒ f α → (α → f β) → f β (=<<) ∷ Monad f ⇒ (α → f β) → (f α → f β)
I think the argument I would make is that (<**>) and (=<<) shouldn't have been added in the first place.
Concerning the addition of (=<<), I'm actually using it more often than the original (>>=). That's because it plays well with function composition, which is left to right. Here an example taken from some code I wrote: runMaker m = sequence_ . G.topsort' . rules2Graph . snd =<< runWriterT m (Arguably, I should should have used (<=<) and tacked a ($) at the end if want an explicit argument, but I'm unclear about the fixities of (<=<).) Regards, Heinrich Apfelmus -- http://apfelmus.nfshost.com

Heinrich Apfelmus wrote:
Johan Tibell wrote:
I think the argument I would make is that (<**>) and (=<<) shouldn't have been added in the first place.
Concerning the addition of (=<<), I'm actually using it more often than the original (>>=). That's because it plays well with function composition, which is left to right.
Oops, I meant to write "right to left". Regards, Heinrich Apfelmus -- http://apfelmus.nfshost.com

On Wed, Apr 07, 2010 at 04:12:24PM +0200, Bas van Dijk wrote:
On Wed, Apr 7, 2010 at 3:58 PM, Felipe Lessa
wrote: Simmetry, as the ticket says.
Indeed, I would like to emphasize that my main reason for adding a flipped fmap is symmetry. I find it hard to explain why <$$> shouldn't be in this list:
(<$>) ∷ Functor f ⇒ (α → β) → (f α → f β) (<$$>) ∷ Functor f ⇒ f α → (α → β) → f β
(<*>) ∷ Applicative f ⇒ f (α → β) → (f α → f β) (<**>) ∷ Applicative f ⇒ f α → f (α → β) → f β
(>>=) ∷ Monad f ⇒ f α → (α → f β) → f β (=<<) ∷ Monad f ⇒ (α → f β) → (f α → f β)
Let me point out that (<**>) is NOT defined as flip (<*>)! In fact it is defined as (<**>) = liftA2 (flip ($)) which is quite different, since it performs effects in the opposite order from flip (<*>). So arguing for (<$$>) as something parallel to (<**>) is a bit misleading. I don't know whether this lends support to one argument or another; I'm personally fairly neutral on the proposal, but I thought this was important to point out. -Brent

Hi!
On Wed, Apr 7, 2010 at 3:58 PM, Felipe Lessa
On Wed, Apr 07, 2010 at 03:33:51PM +0200, Johan Tibell wrote:
Yet, if we add all the function compositions that some group of people use in their code our APIs get much more complicated.
I completely agree, but I think you're overreacting to this proposal (no offense intended, please :]). I don't see a tendency of adding every combinator to the libraries, and I don't think this proposal will change anything.
I'm certainly trying to make a general argument that's larger than this proposal and the important part I want to get across is the criteria used to decide what functions to add to the (base) libraries. In particular I want us to establish that the the following arguments aren't strong enough: - X people use this composition a lot so we should add it. - We added something like this before (e.g. added flipped versions of some operators) so doing it again is fine. Here are some good reasons to add something to an API: - X is not expressible using the current API (or this very difficult/error prone to express). - X is cannot be written efficiently (in terms of run-time performance/space usage) using the current API. - The API exports function X but what it really should have exported was combinators Y and Z (that e.g. make the API more general/composable/etc). Cheers, Johan

On 7 April 2010 15:39, Johan Tibell
In particular I want us to establish that the the following arguments aren't strong enough:
- X people use this composition a lot so we should add it.
If instead its "people NAME this composition a lot" then it should absolutely be added, so that the name chosen can become standard, improving code readability. -- Brian_Brunswick____brian@ithil.org____Wit____Disclaimer____!Shortsig_rules!

On 04/07/10 09:58, Felipe Lessa wrote:
<$$> will be as concise and useful as<$>, maybe even more, because `flip fmap` isn't valid.
This is the annoying part. Aw, Haskell! I suppose we could name the combinator `flipfmap`... and it would be clear what it meant... I disagree with the consistency argument. I don't think <*> -> <**> is a very good precedent. It has confused me. Far more people are familiar with functor than applicative (so this precedent would be applied mostly to an audience who's unfamiliar with it). >>= -> =<< , although perhaps silly, at least looks enough like a mirrored version that you can guess... I'd say "let's fix the fixity of fmap!" except we can't because Prelude exports it. Besides, IMHO fixity isn't too big a deal, because one can use parentheses and they're rather less confusing to read than things being in the "wrong" order or expressions using symbol-operators that the reader doesn't know. I've used `fmap`, infix like that, sometimes... although more recently I've come to think that it's not necessary to use infix operators at all for clarity. A thought: for
do m1 m2 m3 <$$> bigPieceOfCodeThatVisuallyBreaks theSequentialNatureOfADoExpression how about using do m1 m2 flip fmap m3 $ bigPieceOfCodeThatVisuallyBreaks theSequentialNatureOfADoExpression ? (not sure though.. I like using "forM_" more than "flip mapM_"..)
-Isaac

Felipe Lessa wrote:
<$$> will be as concise and useful as <$>, maybe even more, because `flip fmap` isn't valid.
2) Simmetry, as the ticket says.
If we want to keep the analogies complete then we'll need to add ($$)=flip($) as well. As a prefix function it has a perspicuous type (type raising (Smullyan's thrush), aka CPS translation) and I've used it in a number of projects because of that. All the same, I would not consider it worthwhile to add to any library (excepting one which contains Data.Smullyan :) And it only opens the way for defining (!$$), and then why not add (), (),... Every combinator has its place, but often that place is in a local module so that users/maintainers can easily figure out what your line noise means. -- Live well, ~wren

Lets sum up the discussion so far for adding (<$$>) ∷ Functor f ⇒ f α → (α → β) → f β (<$$>) = flip (<$>) to Data.Functor: +1 Bas van Dijk: + Adds symmetry to the existing API. + Useful for not breaking the sequential nature of do-expressions. + Likes that the name <$$> is consistent with <**>. - Doesn't like the name that much because its "undirectional". +1 Nicolas Puillard + Likes the consistent name. +1 Felipe Lessa + Has needed <$$> many times. + "<$$> will be as concise and useful as <$>, maybe even more, because `flip fmap` isn't valid." + Adds symmetry to the existing API. +1 Edward Kmett + Complexity budget is hardly breaked because the function is added to a single module. + "Explaining away its absence is harder than justifying its inclusion." -1 Johan Tibell: - Makes the library more complex. - Fears a trend of adding flipped variants for every operator. - More operators make user code harder to understand. - "(<**>) and (=<<) shouldn't have been added in the first place.... should we really add flipped versions of everything because these exists?" -1 Jesper Louis Andersen: - "Personally, I wouldn't add it". + "But it cannot hurt since only 0.1% of packages are affected". -1 Isaac Dupree: - Disagrees with the consistency argument. 0 Brent Yorhey: 0 (<**>) is NOT defined as flip (<*>)...(<**>) performs effects in the opposite order from flip (<*>). 0 I'm personally fairly neutral on the proposal ? Brian Brunswick ? Heinrich Apfelmus So +4 and -3 so far. I must say that Brent Yorheys comment about (<**>) not being flip (<*>) has made the 'symmetry' argument less convincing and has moved me a bit closer to the - camp. However, I'm still for adding it because it can make code nicer. It would help if some more people can give their +1s or -1s so we will have some bigger numbers. Thanks, Bas

On Thu, Apr 8, 2010 at 9:45 AM, Bas van Dijk
I must say that Brent Yorheys comment about (<**>) not being flip (<*>) has made the 'symmetry' argument less convincing and has moved me a bit closer to the - camp. However, I'm still for adding it because it can make code nicer.
They -- <**> and <$$> -- are symmetric in spirit. In the case of <$> and <$$>, the order in which things are evaluated doesn't matter. So we may say that <*>, <$>, <**> and <$$> are "always read from left to right" if we want to. Well, at least that's how I think ;). I too would like to see more people reporting their thoughts on this issue. Cheers, -- Felipe.

On Thu, 2010-04-08 at 14:04 -0300, Felipe Lessa wrote:
On Thu, Apr 8, 2010 at 9:45 AM, Bas van Dijk
wrote: I must say that Brent Yorheys comment about (<**>) not being flip (<*>) has made the 'symmetry' argument less convincing and has moved me a bit closer to the - camp. However, I'm still for adding it because it can make code nicer.
They -- <**> and <$$> -- are symmetric in spirit.
The equational law relating <$> to <*> for Applicative instances is f <$> a = return f <*> a We analogously have a <$$> f = a <**> return f as well. So the analogy between <$$> and <**> holds. jcc

+1 from me for inclusion of <$$>. Mainly because of the symmetry argument. When you look at the types of (<*>), (<**>); (>>=), (=<<) and (<$>) you can expect there to be a operator with (<$$>)'s type. Its non-existence is surprising. I like the law-of-least-surprise in library design. I do not like the specific symbol <$$>. It is similar to <**> which is nice, but I also don't like <**>. I prefer some sort of visual indication of direction. Like (>>=) versus (=<<) or (⋙) versus (⋘). But in this case history wins over aesthetics. Roel

On 04/08/10 13:10, Jonathan Cast wrote:
The equational law relating<$> to<*> for Applicative instances is
f<$> a = return f<*> a
We analogously have
a<$$> f = a<**> return f
as well. So the analogy between<$$> and<**> holds.
This parallelism also suggests to me that <$$> should be placed (only) in Control.Applicative, which is where <*>, <$>, and <**> reside. Yeah, I know that's annoying... -Isaac

On Thu, Apr 8, 2010 at 3:38 PM, Isaac Dupree wrote: This parallelism also suggests to me that <$$> should be placed (only) in
Control.Applicative, which is where <*>, <$>, and <**> reside. Yeah, I know
that's annoying... <$> is defined or re-exported by both Data.Functor and Control.Applicative.
This parallel would probably suggest exporting it from both Data.Functor and
Control.Applicative, however.
-Edward Kmett

On Thu, 8 Apr 2010 16:06:12 -0400, Edward Kmett
On Thu, Apr 8, 2010 at 3:38 PM, Isaac Dupree
wrote:
This parallelism also suggests to me that <$$> should be placed (only) in Control.Applicative, which is where <*>, <$>, and <**> reside. Yeah, I know that's annoying...
<$> is defined or re-exported by both Data.Functor and Control.Applicative. This parallel would probably suggest exporting it from both Data.Functor and Control.Applicative, however.
Sure it make sense. -- Nicolas Pouillard http://nicolaspouillard.fr

On Thu, Apr 8, 2010 at 9:38 PM, Isaac Dupree
This parallelism also suggests to me that <$$> should be placed (only) in Control.Applicative, which is where <*>, <$>, and <**> reside. Yeah, I know that's annoying...
That's indeed annoying. What about removing <$> and <$ from Control.Applicative? One advantage is that this reduces the complexity tax of Control.Applicative. One disadvantage is that this will surely break some code. Especially because, for some weird reason, Data.Functor is not know to hoogle. http://haskell.org/hoogle/?q=Data.Functor And <$> is reported to be only exported by Control.Applicative http://haskell.org/hoogle/?hoogle=%3C%24%3E sigh... Let's save this for a new proposal however... Bas P.S. Jonathan, thanks for the equational law relating <$$> and <**>: a <$$> f = a <**> return f this has strongly put me back in the +1 camp :-)

I'd strongly discourage removing <$> from Control.Applicative, as it has
been there since the start and basically every single client of
Control.Applicative would break and have to add a second import.
The idiom of foo <$> bar <*> baz <*> ... is the whole point of using an
Applicative after all!
I laud the goal of everything having exactly one place to be, but here I
think practical considerations override.
-Edward Kmett
On Thu, Apr 8, 2010 at 4:07 PM, Bas van Dijk
On Thu, Apr 8, 2010 at 9:38 PM, Isaac Dupree
This parallelism also suggests to me that <$$> should be placed (only) in Control.Applicative, which is where <*>, <$>, and <**> reside. Yeah, I know that's annoying...
That's indeed annoying.
What about removing <$> and <$ from Control.Applicative?
One advantage is that this reduces the complexity tax of Control.Applicative.
One disadvantage is that this will surely break some code. Especially because, for some weird reason, Data.Functor is not know to hoogle.
http://haskell.org/hoogle/?q=Data.Functor
And <$> is reported to be only exported by Control.Applicative
http://haskell.org/hoogle/?hoogle=%3C%24%3E
sigh...
Let's save this for a new proposal however...
Bas
P.S. Jonathan, thanks for the equational law relating <$$> and <**>: a <$$> f = a <**> return f this has strongly put me back in the +1 camp :-) _______________________________________________ Libraries mailing list Libraries@haskell.org http://www.haskell.org/mailman/listinfo/libraries

On 04/08/10 16:07, Bas van Dijk wrote:
... Especially because, for some weird reason, Data.Functor is not know to hoogle.
http://haskell.org/hoogle/?q=Data.Functor
And<$> is reported to be only exported by Control.Applicative
oh gee, there seems to be some confusion. At least, I was confused. Well, here's a list from the GHC(i) 6.12.1 prompt about what's in Data.Functor:
:browse Data.Functor (<$>) :: (Functor f) => (a -> b) -> f a -> f b class Functor f where fmap :: (a -> b) -> f a -> f b (<$) :: a -> f b -> f a

Bas van Dijk wrote:
Hello,
I would like to propose adding a flipped variant of <$> to Data.Functor:
(<$$>) ∷ Functor f ⇒ f α → (α → β) → f β (<$$>) = flip (<$>)
Please see the ticket for motivation and patch:
I'm also not in favor. There is good motivation for having both of (>>=) and (=<<): * the (=<<) variant provides an applicative style by giving a name for Kleisli application. * and the (>>=) variant provides an imperative style for those who like that sort of thing. There is good reason for having (<$>) as an alternative to fmap: * It also serves to support the applicative style by giving a name for functorial application. There is good reason to have (<*>): * It supports the use of (<$>) for multi-argument functions. But I don't see much benefit to having (<**>) let alone (<$$>), when they are easily defined by using flip. The other clutter of Applicative ((<*), (*>),...) can be motivated by performance concerns for certain applicative combinator parsers, but I'm not a big fan of them either. (<$$>) offers no performance benefit, does not offer a definition for a perspicuous type[1], and does not seem to offer significant improvement in code legibility which could not be obtained from a local definition. -- Live well, ~wren [1] For example, * (=<<) is perspicuous because it names Kleisli application. Given a prefix name like 'star' it would also be perspicuous for point-free style where it serves as the superscript star operator used in category theory. Having both (=<<) and 'star' could even be justified for similar reasons to having both 'fmap' and (<$>): supporting both applicative and pointless styles. * forM_ is perspicuous because it captures an intuitive notion of imperative style, even though mapM_ captures an applicative version of a similar notion. * (flip lookup) would be perspicuous for the same reasons as (=<<): it supports the idea of transforming an assoc-list into the function that list represents. Similar variations on this theme apply to indexing functions for Data.Map where the (Map a b -> (a->b)) ordering supports the idea of transforming the map into its associated function. * (curry . (flip (uncurry foldr))), (curry . (flip (uncurry either))), and (curry . (flip (uncurry maybe))) would be perspicuous for capturing the transformation of concrete types into their Church encodings.

But I don't see much benefit to having (<**>) let alone (<$$>), when they are easily defined by using flip. The other clutter of Applicative ((<*), (*>),...) can be motivated by performance concerns for certain applicative combinator parsers, but I'm not a big fan of them either.
While this is a valid concern with regards to <$$>, <**> cannot be defined in terms of flip as it swaps the order of the effects as well. -Edward Kmett

wren ng thornton wrote:
Edward Kmett wrote:
<**> cannot be defined in terms of flip as it swaps the order of the effects as well.
But I thought:
(<**>) = liftA2 (flip ($))
:)
If (<**>) were to have been defined as flip(liftA2(flip($))), then I would be supportive of it. My definition has the same perspicuous type as (<*>) but adding support for non-LtR ordering of effects/evaluation, which seems to be the goal of the (<**>) combinator. However, (<**>) as it is actually defined forces one to give up the applicative style in order to alter evaluation ordering. In so doing it does not come to support another style and therefore simply looks like a wart on the API. Someone might could make an argument for (<**>) supporting a sort of object-oriented style in terms of evaluation order, but that style is not otherwise supported by the Applicative combinators, and so I wouldn't find it convincing. -- Live well, ~wren

On Thu, Apr 8, 2010 at 6:16 PM, wren ng thornton wrote: wren ng thornton wrote: Edward Kmett wrote: <**> cannot be defined in terms of flip as it swaps the order of the
effects as well. But I thought: (<**>) = liftA2 (flip ($)) :) =) If (<**>) were to have been defined as flip(liftA2(flip($))), then I would
be supportive of it. My definition has the same perspicuous type as (<*>)
but adding support for non-LtR ordering of effects/evaluation, which seems
to be the goal of the (<**>) combinator. However, (<**>) as it is actually
defined forces one to give up the applicative style in order to alter
evaluation ordering. In so doing it does not come to support another style
and therefore simply looks like a wart on the API. Someone might could make
an argument for (<**>) supporting a sort of object-oriented style in terms
of evaluation order, but that style is not otherwise supported by the
Applicative combinators, and so I wouldn't find it convincing. As written
x <**> f =liftA2 (flip ($)) x f = flip id <$> x <*> f
keeps the order of effects reading from left to right, to be consistent with
the other applicative combinators as opposed to the other candidate:
I think in many ways the strict left to right effect evaluation order is
what makes Applicative code readable. You don't have to reason piecemeal
about the order of effects.
Both the naive flip (<*>) and your proposed
flip (liftA2 (flip ($)) x y = flip (liftA2 (flip id)) x y = liftA2 (flip id)
y x = flip id <$> y <*> x
sacrifice that important property.
-Edward Kmett

Edward Kmett wrote:
I think in many ways the strict left to right effect evaluation order is what makes Applicative code readable.
I was going to mention that as the potential downside. However, I'd interpret my version in the same vein as ($!). That is: evaluate the argument, evaluate the function, invoke function on argument. The ($!) combinator violates the standard call-by-need ordering, just as flip(<**>) violates the standard left-to-right ordering, but people don't generally find ($!) unintuitive... Of course, both are CPS transformations for the sake of controlling order of evaluation. The ($!) and flip(<**>) versions allow this transformation to be implicit by retaining the usual direct-style ordering of application; whereas flip($!) and (<**>) make the CPS ordering of application explicit. Reasoning in CPS doesn't bother me, but I think it's more elegant to be locally consistent about which style is being used. -- Live well, ~wren

On Thu, Apr 8, 2010 at 11:21 PM, wren ng thornton
There is good motivation for having both of (>>=) and (=<<): * the (=<<) variant provides an applicative style by giving a name for Kleisli application. * and the (>>=) variant provides an imperative style for those who like that sort of thing.
Applying the same reasoning to <$> and <$$>: * <$> serves to support the applicative style by giving a name for functorial application. (as you mentioned) * <$$> provides an imperative style for those who like that sort of thing. As in: do m1 m2 m3 <$$> bigPieceOfCodeThat whenUsingFlipFmap willVisuallyBreak theImperativeNature ofADoExpression

Bas van Dijk wrote:
On Thu, Apr 8, 2010 at 11:21 PM, wren ng thornton
wrote: There is good motivation for having both of (>>=) and (=<<): * the (=<<) variant provides an applicative style by giving a name for Kleisli application. * and the (>>=) variant provides an imperative style for those who like that sort of thing.
Applying the same reasoning to <$> and <$$>:
* <$> serves to support the applicative style by giving a name for functorial application. (as you mentioned) * <$$> provides an imperative style for those who like that sort of thing. As in:
do m1 m2 m3 <$$> bigPieceOfCodeThat whenUsingFlipFmap willVisuallyBreak theImperativeNature ofADoExpression
That is more of a conflation of applicative and imperative styles. The style of imperative languages generally prefers: do m1 m2 x <- m3 bigUglyBlah x Frequently further breaking up the big expression and using more temporaries. The reason (>>=) supports imperative style is *not* because we can say, do m1 m2 m3 >>= f The reason (>>=) supports imperative style is *exactly* because we can say m1 >>= \_ -> m2 >>= \_ -> m3 >>= \x -> bigUglyBlah x This old habit of aligning the binds is what lead prople to thinking of monads as capturing "semicolon overloading", from whence the do-notation originates. There has been no similar argument that (<$$>) captures any intuitive notion from the imperative style. Similarly, forM_ captures the intuitive imperative notion of for-loops *not* because it happens to take arguments in reverse order, but because the order of arguments is expressly similar to the for-loop notation used in imperative languages. Imperative style is not about the order of things, it is about a mindset with which we think about the structure of programs. The same goes for applicative style, points-free style, and object-oriented style. -- Live well, ~wren

Hello,
the deadline for the proposal to add (<$$>) = flip (<$>) to
Data.Functor has passed.
In the end there wasn't overwhelming support for this so I will
resolve this ticket as 'wontfix' after the weekend.
regards,
Bas
On Wed, Apr 7, 2010 at 11:13 AM, Bas van Dijk
Hello,
I would like to propose adding a flipped variant of <$> to Data.Functor:
(<$$>) ∷ Functor f ⇒ f α → (α → β) → f β (<$$>) = flip (<$>)
Please see the ticket for motivation and patch:
http://hackage.haskell.org/trac/ghc/ticket/3962
Discussion period: 2 weeks.
regards,
Bas
participants (13)
-
Bas van Dijk
-
Brent Yorgey
-
Brian Brunswick
-
Edward Kmett
-
Felipe Lessa
-
Heinrich Apfelmus
-
Isaac Dupree
-
Jesper Louis Andersen
-
Johan Tibell
-
Jonathan Cast
-
Nicolas Pouillard
-
Roel van Dijk
-
wren ng thornton