Polymorphism in the Prelude

Hi libraries, Let me try to sum up the general sentiment I've seen: Having lots of polymorphism in the Prelude is great, but for two problems: 1) It's very confusing to novices. 2) In the case of using Control.Category definitions: kind-polymorphism is not portable I wish to ignore (2) for now, as it's a smaller concern given that it affects only a portion of the proposed changes. As a way to mitigate (1), I have been thinking of proposing something almost exactly along the lines of http://comments.gmane.org/gmane.comp.lang.haskell.glasgow.user/23719 (thanks for posting that link -- saved me from writing up the same thing!). But, after reading that thread, I tend to agree that tweaking the module system seems the wrong way to deal with helping novices. In designing my own libraries, my general guideline is to make the easy thing easy and make the hard thing only slightly less easy. Spurred on by Erik Hesselink's comment (http://www.haskell.org/pipermail/libraries/2014-June/023174.html), what if we just have two versions of `base` modules, the "normal" one that exports more monomorphic definitions (which novices are more likely to use) and a "Poly" one that exports more polymorphic definitions. For example: {{{ {-# LANGUAGE NoImplicitPrelude #-} import Prelude.Poly import Data.List.Poly import Data.Foldable import Control.Monad.Poly }}} and then it just works. Pros: - Not disruptive to current status quo. - No change in error messages for novices. - Can actually be implemented without *any* changes to `base` -- I could upload this solution to Hackage today. Cons: - Maintaining two copies of export lists. - Needs NoImplicitPrelude pragma. - Overhead of remembering which modules have a "Poly" version and which don't. - Somewhat ugly. Even as I write this, I'm not sure that this is at all a good idea. But, to me, it's really intriguing that the solution is achievable today, with no difficulty. I would wager that if these Poly modules were out in the wild today, we might all grumble at them, but I don't know if there would be a movement to change the Prelude. Richard

Having attempted to program with NoImplicitPrelude "in anger", I personally think this fix is worse than the disease and I'm personally -1. In some sense, the current path we're taking forward is actually substantially similar except the non-generalized versions are just the haskell2010 and haskell98 packages, which work well for the kind of trivial classroom exercises needed for the first semester worth of coursework, but desire to work with the rest of the library ecosystem provides gentle pressure to encourage people to learn the rest. The difference is the vast majority of users aren't constantly plagued by the demand they use extensions to get what should really be baseline tools. In the long term, yes we might want to embrace Category and other abstractions. The main issue I have is that it is very hard to motivate through Prelude in that there is only one Prelude type anyone can point to that is an instance. -Edward
On Jun 16, 2014, at 9:46 AM, Richard Eisenberg
wrote: Hi libraries,
Let me try to sum up the general sentiment I've seen:
Having lots of polymorphism in the Prelude is great, but for two problems: 1) It's very confusing to novices. 2) In the case of using Control.Category definitions: kind-polymorphism is not portable
I wish to ignore (2) for now, as it's a smaller concern given that it affects only a portion of the proposed changes.
As a way to mitigate (1), I have been thinking of proposing something almost exactly along the lines of http://comments.gmane.org/gmane.comp.lang.haskell.glasgow.user/23719 (thanks for posting that link -- saved me from writing up the same thing!). But, after reading that thread, I tend to agree that tweaking the module system seems the wrong way to deal with helping novices.
In designing my own libraries, my general guideline is to make the easy thing easy and make the hard thing only slightly less easy. Spurred on by Erik Hesselink's comment (http://www.haskell.org/pipermail/libraries/2014-June/023174.html), what if we just have two versions of `base` modules, the "normal" one that exports more monomorphic definitions (which novices are more likely to use) and a "Poly" one that exports more polymorphic definitions. For example:
{{{ {-# LANGUAGE NoImplicitPrelude #-}
import Prelude.Poly import Data.List.Poly import Data.Foldable import Control.Monad.Poly }}}
and then it just works.
Pros: - Not disruptive to current status quo. - No change in error messages for novices. - Can actually be implemented without *any* changes to `base` -- I could upload this solution to Hackage today.
Cons: - Maintaining two copies of export lists. - Needs NoImplicitPrelude pragma. - Overhead of remembering which modules have a "Poly" version and which don't. - Somewhat ugly.
Even as I write this, I'm not sure that this is at all a good idea. But, to me, it's really intriguing that the solution is achievable today, with no difficulty. I would wager that if these Poly modules were out in the wild today, we might all grumble at them, but I don't know if there would be a movement to change the Prelude.
Richard _______________________________________________ Libraries mailing list Libraries@haskell.org http://www.haskell.org/mailman/listinfo/libraries

* The big issue I have is the one I already mentioned -- the fact that the price is born by every user going forward. You spend a line of boiler plate setting up NoImplicitPrelude, and an import of Prelude.Whatever so all users pay for it forever. The current plan on the other hand has 0 tax for users on an ongoing basis and most of the boilerplate users do have melts away. * A far less compelling, but tedious technical issue is if you import a bunch of these Foo.Poly modules, on windows (with certain build tools?) with enough modules with the same final name .Poly you can run into linker problems, we've actually had users run into this with lens. -Edward
On Jun 16, 2014, at 10:09 AM, Erik Hesselink
wrote: On Mon, Jun 16, 2014 at 4:07 PM, Edward Kmett
wrote: Having attempted to program with NoImplicitPrelude "in anger", I personally think this fix is worse than the disease and I'm personally -1. Out of curiosity, what were the problems you encountered?
Erik

Note: we already have several of these alternate Preludes out there, which have gained little traction, largely because many users aren't willing to incur another package dependency for convenience. prelude-prime classy-prelude fugue -Edward
On Jun 16, 2014, at 9:46 AM, Richard Eisenberg
wrote: I would wager that if these Poly modules were out in the wild today, we might all grumble at them, but I don't know if there would be a movement to change the Prelude.
Richard _______________________________________________ Libraries mailing list Libraries@haskell.org http://www.haskell.org/mailman/listinfo/libraries

How do you know if alternate prelude are gaining traction? Libraries
authors are always going to hesitate to include another package, but they
are really for application developers. Are you using download statistics?
On Mon, Jun 16, 2014 at 7:30 AM, Edward Kmett
Note: we already have several of these alternate Preludes out there, which have gained little traction, largely because many users aren't willing to incur another package dependency for convenience.
prelude-prime classy-prelude fugue
-Edward
On Jun 16, 2014, at 9:46 AM, Richard Eisenberg
wrote: I would wager that if these Poly modules were out in the wild today, we might all grumble at them, but I don't know if there would be a movement to change the Prelude.
Richard _______________________________________________ Libraries mailing list Libraries@haskell.org http://www.haskell.org/mailman/listinfo/libraries
Libraries mailing list Libraries@haskell.org http://www.haskell.org/mailman/listinfo/libraries

Based on raw download stats:
basic-prelude has probably received the most traction. It has ~8k downloads.
classy-prelude decays to ~4k downloads.
general-prelude ~180.
The other two I mentioned have had ~100 each.
By way of comparison something like, say, 'profunctors' has ~50k downloads.
That said, I spend an awful lot of time talking to people at conventions
and hackathons, and my response was mostly anecdotal based on responses
I've received as I've asked around to find out what people want in the
Prelude going forward.
-Edward
On Mon, Jun 16, 2014 at 12:58 PM, Greg Weber
How do you know if alternate prelude are gaining traction? Libraries authors are always going to hesitate to include another package, but they are really for application developers. Are you using download statistics?
On Mon, Jun 16, 2014 at 7:30 AM, Edward Kmett
wrote: Note: we already have several of these alternate Preludes out there, which have gained little traction, largely because many users aren't willing to incur another package dependency for convenience.
prelude-prime classy-prelude fugue
-Edward
On Jun 16, 2014, at 9:46 AM, Richard Eisenberg
wrote: I would wager that if these Poly modules were out in the wild today, we might all grumble at them, but I don't know if there would be a movement to change the Prelude.
Richard _______________________________________________ Libraries mailing list Libraries@haskell.org http://www.haskell.org/mailman/listinfo/libraries
Libraries mailing list Libraries@haskell.org http://www.haskell.org/mailman/listinfo/libraries

On Mon, Jun 16, 2014 at 10:33 AM, Edward Kmett
Based on raw download stats:
basic-prelude has probably received the most traction. It has ~8k downloads.
classy-prelude decays to ~4k downloads.
general-prelude ~180.
The other two I mentioned have had ~100 each.
By way of comparison something like, say, 'profunctors' has ~50k downloads.
That is interesting, thank you for sharing! Are you using direct downlaods of profunctor? because profunctor is designed to be a library dependency (lens depends on it as do 20+ other packages), whereas with classy-prelude users are advised to not use it as a library dependency and only use it for their applications. There is only really one library with usage that depend on classy-prelude, classy-prelude-conduit, and only classy-prelude-yesod depends on that, and nothing depends on that, they are all designed for application writers, not as library dependencies. Does it makes sense to make a direct comparison of total downloads for these 2 different use cases?
That said, I spend an awful lot of time talking to people at conventions and hackathons, and my response was mostly anecdotal based on responses I've received as I've asked around to find out what people want in the Prelude going forward.
-Edward
On Mon, Jun 16, 2014 at 12:58 PM, Greg Weber
wrote: How do you know if alternate prelude are gaining traction? Libraries authors are always going to hesitate to include another package, but they are really for application developers. Are you using download statistics?
On Mon, Jun 16, 2014 at 7:30 AM, Edward Kmett
wrote: Note: we already have several of these alternate Preludes out there, which have gained little traction, largely because many users aren't willing to incur another package dependency for convenience.
prelude-prime classy-prelude fugue
-Edward
On Jun 16, 2014, at 9:46 AM, Richard Eisenberg
wrote: I would wager that if these Poly modules were out in the wild today, we might all grumble at them, but I don't know if there would be a movement to change the Prelude.
Richard _______________________________________________ Libraries mailing list Libraries@haskell.org http://www.haskell.org/mailman/listinfo/libraries
Libraries mailing list Libraries@haskell.org http://www.haskell.org/mailman/listinfo/libraries

On Tue, Jun 17, 2014 at 3:59 AM, Greg Weber
On Mon, Jun 16, 2014 at 10:33 AM, Edward Kmett
wrote: Based on raw download stats:
basic-prelude has probably received the most traction. It has ~8k downloads.
classy-prelude decays to ~4k downloads.
general-prelude ~180.
The other two I mentioned have had ~100 each.
By way of comparison something like, say, 'profunctors' has ~50k downloads.
That is interesting, thank you for sharing! Are you using direct downlaods of profunctor? because profunctor is designed to be a library dependency (lens depends on it as do 20+ other packages), whereas with classy-prelude users are advised to not use it as a library dependency and only use it for their applications. There is only really one library with usage that depend on classy-prelude, classy-prelude-conduit, and only classy-prelude-yesod depends on that, and nothing depends on that, they are all designed for application writers, not as library dependencies.
Does it makes sense to make a direct comparison of total downloads for these 2 different use cases?
It isn't a perfect comparison, but if we're looking at adoption, adoption is adoption regardless of whether the library is sold for a very limited application-oriented usecase. Haskell is the sum of library authors and application authors (and students who will probably never write a library). All we're doing is bringing the non-controversial parts of base that people already use every day into the standard Prelude, where it can benefit each group. A proposal that says "well, application authors can just use X" ignores the large mass of library authors out there when it just doesn't have to. we have a straightforward path to monotonic improvement over the status quo, lets take it. Again, my reaction is mostly measured by the fact that I've actively asked folks in person about this as I travel around to user groups and ask "what is it that the core library committee could do that would make Haskell better for you" and have received a lot of feedback, it isn't just driven by those numbers. -Edward

Forgive a perhaps newbie question, but: How do I use the haskell2010 package? An earlier recommendation in this thread for novices is to "use haskell2010" to reduce the upcoming extra polymorphism in the prelude. How is this done, in practice? My guess is that we have to use several command-line flags to hide the `base` package and make the `haskell2010` package visible. Some experimenting got `ghc -package haskell2010 -hide-package base Foo.hs` to work. These flags can't even be embedded in an OPTIONS_GHC pragma.
In any case, it's a bit of a hoop for novices to jump through, especially if they aren't being guided by a teacher.
I tend to agree that taxing the large quantity of experienced users for the benefit of novices is wrong-headed. But, I still think we need a nice, simple story to get new folks off the ground. Haskell prides itself on its beauty, and requiring several obscure and (at first) inscrutable command line flags to get decent error messages for a novice is not beautiful.
Richard
On Jun 17, 2014, at 7:58 AM, Edward Kmett
On Tue, Jun 17, 2014 at 3:59 AM, Greg Weber
wrote: On Mon, Jun 16, 2014 at 10:33 AM, Edward Kmett
wrote: Based on raw download stats: basic-prelude has probably received the most traction. It has ~8k downloads.
classy-prelude decays to ~4k downloads.
general-prelude ~180.
The other two I mentioned have had ~100 each.
By way of comparison something like, say, 'profunctors' has ~50k downloads.
That is interesting, thank you for sharing! Are you using direct downlaods of profunctor? because profunctor is designed to be a library dependency (lens depends on it as do 20+ other packages), whereas with classy-prelude users are advised to not use it as a library dependency and only use it for their applications. There is only really one library with usage that depend on classy-prelude, classy-prelude-conduit, and only classy-prelude-yesod depends on that, and nothing depends on that, they are all designed for application writers, not as library dependencies.
Does it makes sense to make a direct comparison of total downloads for these 2 different use cases?
It isn't a perfect comparison, but if we're looking at adoption, adoption is adoption regardless of whether the library is sold for a very limited application-oriented usecase. Haskell is the sum of library authors and application authors (and students who will probably never write a library). All we're doing is bringing the non-controversial parts of base that people already use every day into the standard Prelude, where it can benefit each group.
A proposal that says "well, application authors can just use X" ignores the large mass of library authors out there when it just doesn't have to. we have a straightforward path to monotonic improvement over the status quo, lets take it.
Again, my reaction is mostly measured by the fact that I've actively asked folks in person about this as I travel around to user groups and ask "what is it that the core library committee could do that would make Haskell better for you" and have received a lot of feedback, it isn't just driven by those numbers.
-Edward

ghc-pkg hide base
ghc-pkg expose haskell2010
Now when you run ghc from the command line or start ghci you'll get
haskell2010 by default.
Vice versa to switch back.
-Edward
On Tue, Jun 17, 2014 at 10:24 AM, Richard Eisenberg
Forgive a perhaps newbie question, but: How do I use the haskell2010 package? An earlier recommendation in this thread for novices is to "use haskell2010" to reduce the upcoming extra polymorphism in the prelude. How is this done, in practice? My guess is that we have to use several command-line flags to hide the `base` package and make the `haskell2010` package visible. Some experimenting got `ghc -package haskell2010 -hide-package base Foo.hs` to work. These flags can't even be embedded in an OPTIONS_GHC pragma.
In any case, it's a bit of a hoop for novices to jump through, especially if they aren't being guided by a teacher.
I tend to agree that taxing the large quantity of experienced users for the benefit of novices is wrong-headed. But, I still think we need a nice, simple story to get new folks off the ground. Haskell prides itself on its beauty, and requiring several obscure and (at first) inscrutable command line flags to get decent error messages for a novice is not beautiful.
Richard
On Jun 17, 2014, at 7:58 AM, Edward Kmett
wrote: On Tue, Jun 17, 2014 at 3:59 AM, Greg Weber
wrote: On Mon, Jun 16, 2014 at 10:33 AM, Edward Kmett
wrote: Based on raw download stats:
basic-prelude has probably received the most traction. It has ~8k downloads.
classy-prelude decays to ~4k downloads.
general-prelude ~180.
The other two I mentioned have had ~100 each.
By way of comparison something like, say, 'profunctors' has ~50k downloads.
That is interesting, thank you for sharing! Are you using direct downlaods of profunctor? because profunctor is designed to be a library dependency (lens depends on it as do 20+ other packages), whereas with classy-prelude users are advised to not use it as a library dependency and only use it for their applications. There is only really one library with usage that depend on classy-prelude, classy-prelude-conduit, and only classy-prelude-yesod depends on that, and nothing depends on that, they are all designed for application writers, not as library dependencies.
Does it makes sense to make a direct comparison of total downloads for these 2 different use cases?
It isn't a perfect comparison, but if we're looking at adoption, adoption is adoption regardless of whether the library is sold for a very limited application-oriented usecase. Haskell is the sum of library authors and application authors (and students who will probably never write a library). All we're doing is bringing the non-controversial parts of base that people already use every day into the standard Prelude, where it can benefit each group.
A proposal that says "well, application authors can just use X" ignores the large mass of library authors out there when it just doesn't have to. we have a straightforward path to monotonic improvement over the status quo, lets take it.
Again, my reaction is mostly measured by the fact that I've actively asked folks in person about this as I travel around to user groups and ask "what is it that the core library committee could do that would make Haskell better for you" and have received a lot of feedback, it isn't just driven by those numbers.
-Edward

On 2014-06-17 at 16:24:16 +0200, Richard Eisenberg wrote: [...]
In any case, it's a bit of a hoop for novices to jump through, especially if they aren't being guided by a teacher.
I tend to agree that taxing the large quantity of experienced users for the benefit of novices is wrong-headed. But, I still think we need a nice, simple story to get new folks off the ground. Haskell prides itself on its beauty, and requiring several obscure and (at first) inscrutable command line flags to get decent error messages for a novice is not beautiful.
Fwiw, something related was brought up by John Meacham at http://www.haskell.org/pipermail/glasgow-haskell-users/2014-June/025047.html Or maybe one could do something similiar to what was done with /usr/bin/c99, i.e. provide a '/usr/bin/hc2010' (or ghc2010) wrapper for ghc, that would by default force Haskell2010 mode and pull the 'haskell2010' pkg into scope while hiding 'base'

Richard Eisenberg wrote:
Having lots of polymorphism in the Prelude is great, but for two problems: 1) It's very confusing to novices. 2) In the case of using Control.Category definitions: kind-polymorphism is not portable
I wish to ignore (2) for now, as it's a smaller concern given that it affects only a portion of the proposed changes.
In my opinion, Richard missed the most important reason: 3) Gratuitous polymorphism makes code much less readable and much costlier to maintain, usually for almost no gain. One of the biggest strengths of Haskell is semantic clarity. You can often look at a Haskell expression, recognize its type, and then immediately understand exactly what the expression is doing. That is immensely valuable, not only for writing code, but for maintaining and refactoring it over the lifetime of an application, often by people other than the original author. Adding polymorphism to code is semantically lossy. One of the biggest disasters I have ever suffered in software engineering was when someone went through an entire fairly large code base and changed it to use a more polymorphic Prelude, then left the company. Adding the polymorphism was mostly mechanical, but undoing it required hours upon hours of puzzling out the meaning of the code, line by line. And do not relegate Richard's point #1 to CS 101 at university. Most software maintenance is done by the developers with the least Haskell experience. And that is the largest cost of software over time. Polymorphism can be very powerful, of course, and there are a lot of great tools and techniques that use it in various ways. But why force some particular polymorphic generalization down everyone's throat when the cost of enabling it if you want it is essentially zero? If you use a different Prelude in a large project, or in many small projects, take a few minutes to set up your dev environment accordingly. As a case in point: Yesod uses many GHC extensions universally, among them NoImplicitPrelude. These are all listed in the automatically-generated default cabal file; they never need to be typed, and never appear in any source files. There is a single extra line in each file which sets up the whole environment: import Import You can bind that to an editor key if you'd like. You can write scripts. There are packages on Haskell which automate a lot of things. Need I go on with these trivialities? A lot of thought went into making it easy to use GHC extensions. Advanced and experienced developers who need them should have no trouble at all using them, including alternative Preludes. That is not to say that no changes should be made to the Prelude. Now that people are using a number of different alternative Preludes more regularly, I would hope we can use that experience to make much-needed improvements to the default Prelude. But the principal design considerations should be simplicity, ease of use even for beginners, and semantic clarity of code using it. Thanks, Yitz

I find this argument against polymorphism baffling. Do I really have to state the benefits of parametricity here? Probably not. Most likely, there is some specific style of polymorphism in mind going unsaid here, such as ListLike type classes that have tons of methods and don't really have any meaningful laws. Is this the case, or do you *really* mean to argue that polymorphism makes code confusing? If the latter, would you mind explaining why? Please forgive me for any weird autocorrections, typos, or bad grammar. This was written on my phone, which is hard to write and proofread on. Richard Eisenberg wrote:
Having lots of polymorphism in the Prelude is great, but for two problems: 1) It's very confusing to novices. 2) In the case of using Control.Category definitions: kind-polymorphism is not portable
I wish to ignore (2) for now, as it's a smaller concern given that it affects only a portion of the proposed changes.
In my opinion, Richard missed the most important reason: 3) Gratuitous polymorphism makes code much less readable and much costlier to maintain, usually for almost no gain. One of the biggest strengths of Haskell is semantic clarity. You can often look at a Haskell expression, recognize its type, and then immediately understand exactly what the expression is doing. That is immensely valuable, not only for writing code, but for maintaining and refactoring it over the lifetime of an application, often by people other than the original author. Adding polymorphism to code is semantically lossy. One of the biggest disasters I have ever suffered in software engineering was when someone went through an entire fairly large code base and changed it to use a more polymorphic Prelude, then left the company. Adding the polymorphism was mostly mechanical, but undoing it required hours upon hours of puzzling out the meaning of the code, line by line. And do not relegate Richard's point #1 to CS 101 at university. Most software maintenance is done by the developers with the least Haskell experience. And that is the largest cost of software over time. Polymorphism can be very powerful, of course, and there are a lot of great tools and techniques that use it in various ways. But why force some particular polymorphic generalization down everyone's throat when the cost of enabling it if you want it is essentially zero? If you use a different Prelude in a large project, or in many small projects, take a few minutes to set up your dev environment accordingly. As a case in point: Yesod uses many GHC extensions universally, among them NoImplicitPrelude. These are all listed in the automatically-generated default cabal file; they never need to be typed, and never appear in any source files. There is a single extra line in each file which sets up the whole environment: import Import You can bind that to an editor key if you'd like. You can write scripts. There are packages on Haskell which automate a lot of things. Need I go on with these trivialities? A lot of thought went into making it easy to use GHC extensions. Advanced and experienced developers who need them should have no trouble at all using them, including alternative Preludes. That is not to say that no changes should be made to the Prelude. Now that people are using a number of different alternative Preludes more regularly, I would hope we can use that experience to make much-needed improvements to the default Prelude. But the principal design considerations should be simplicity, ease of use even for beginners, and semantic clarity of code using it. Thanks, Yitz _______________________________________________ Libraries mailing list Libraries@haskell.org http://www.haskell.org/mailman/listinfo/libraries

On Wed, Jun 18, 2014 at 08:49:00AM -0400, Jake McArthur wrote:
I find this argument against polymorphism baffling. Do I really have to state the benefits of parametricity here? Probably not. Most likely, there is some specific style of polymorphism in mind going unsaid here, such as ListLike type classes that have tons of methods and don't really have any meaningful laws. Is this the case, or do you *really* mean to argue that polymorphism makes code confusing? If the latter, would you mind explaining why?
Looking back through this thread it seems to me that it is typeclass polymorphism that is being discussed, not parametric polymorphism. Tom

I think it's a pretty clear tradeoff: if you write 'map f xs' you know
that 'xs' must be a list. If you write 'fmap f xs', you know only that
'xs' is a Functor. So you gain flexibility in when you can use 'fmap',
but you lose the local information you get from the more constrained
type of 'map'. The same argument applies when generalizing 'mapM' and
friends. I'm still in favor of generalizing the Prelude functions to
their Foldable/Traversable variants, but the downside is also clear to
me.
This seems like a perfect problem for an IDE to solve, by the way.
Erik
On Wed, Jun 18, 2014 at 2:49 PM, Jake McArthur
I find this argument against polymorphism baffling. Do I really have to state the benefits of parametricity here? Probably not. Most likely, there is some specific style of polymorphism in mind going unsaid here, such as ListLike type classes that have tons of methods and don't really have any meaningful laws. Is this the case, or do you *really* mean to argue that polymorphism makes code confusing? If the latter, would you mind explaining why?
Please forgive me for any weird autocorrections, typos, or bad grammar. This was written on my phone, which is hard to write and proofread on.
Richard Eisenberg wrote:
Having lots of polymorphism in the Prelude is great, but for two problems: 1) It's very confusing to novices. 2) In the case of using Control.Category definitions: kind-polymorphism is not portable
I wish to ignore (2) for now, as it's a smaller concern given that it affects only a portion of the proposed changes.
In my opinion, Richard missed the most important reason:
3) Gratuitous polymorphism makes code much less readable and much costlier to maintain, usually for almost no gain.
One of the biggest strengths of Haskell is semantic clarity. You can often look at a Haskell expression, recognize its type, and then immediately understand exactly what the expression is doing. That is immensely valuable, not only for writing code, but for maintaining and refactoring it over the lifetime of an application, often by people other than the original author.
Adding polymorphism to code is semantically lossy. One of the biggest disasters I have ever suffered in software engineering was when someone went through an entire fairly large code base and changed it to use a more polymorphic Prelude, then left the company. Adding the polymorphism was mostly mechanical, but undoing it required hours upon hours of puzzling out the meaning of the code, line by line.
And do not relegate Richard's point #1 to CS 101 at university. Most software maintenance is done by the developers with the least Haskell experience. And that is the largest cost of software over time.
Polymorphism can be very powerful, of course, and there are a lot of great tools and techniques that use it in various ways. But why force some particular polymorphic generalization down everyone's throat when the cost of enabling it if you want it is essentially zero?
If you use a different Prelude in a large project, or in many small projects, take a few minutes to set up your dev environment accordingly.
As a case in point: Yesod uses many GHC extensions universally, among them NoImplicitPrelude. These are all listed in the automatically-generated default cabal file; they never need to be typed, and never appear in any source files. There is a single extra line in each file which sets up the whole environment:
import Import
You can bind that to an editor key if you'd like. You can write scripts. There are packages on Haskell which automate a lot of things. Need I go on with these trivialities?
A lot of thought went into making it easy to use GHC extensions. Advanced and experienced developers who need them should have no trouble at all using them, including alternative Preludes.
That is not to say that no changes should be made to the Prelude. Now that people are using a number of different alternative Preludes more regularly, I would hope we can use that experience to make much-needed improvements to the default Prelude. But the principal design considerations should be simplicity, ease of use even for beginners, and semantic clarity of code using it.
Thanks, Yitz _______________________________________________ Libraries mailing list Libraries@haskell.org http://www.haskell.org/mailman/listinfo/libraries
_______________________________________________ Libraries mailing list Libraries@haskell.org http://www.haskell.org/mailman/listinfo/libraries

Of course, you can always add type annotations to be more specific
about your types. And that actually might be clearer than having to
remember all the various names for all the various monomorphic
variants. Or it might not.
On Wed, Jun 18, 2014 at 6:06 AM, Erik Hesselink
I think it's a pretty clear tradeoff: if you write 'map f xs' you know that 'xs' must be a list. If you write 'fmap f xs', you know only that 'xs' is a Functor. So you gain flexibility in when you can use 'fmap', but you lose the local information you get from the more constrained type of 'map'. The same argument applies when generalizing 'mapM' and friends. I'm still in favor of generalizing the Prelude functions to their Foldable/Traversable variants, but the downside is also clear to me.
This seems like a perfect problem for an IDE to solve, by the way.
Erik
On Wed, Jun 18, 2014 at 2:49 PM, Jake McArthur
wrote: I find this argument against polymorphism baffling. Do I really have to state the benefits of parametricity here? Probably not. Most likely, there is some specific style of polymorphism in mind going unsaid here, such as ListLike type classes that have tons of methods and don't really have any meaningful laws. Is this the case, or do you *really* mean to argue that polymorphism makes code confusing? If the latter, would you mind explaining why?
Please forgive me for any weird autocorrections, typos, or bad grammar. This was written on my phone, which is hard to write and proofread on.
Richard Eisenberg wrote:
Having lots of polymorphism in the Prelude is great, but for two problems: 1) It's very confusing to novices. 2) In the case of using Control.Category definitions: kind-polymorphism is not portable
I wish to ignore (2) for now, as it's a smaller concern given that it affects only a portion of the proposed changes.
In my opinion, Richard missed the most important reason:
3) Gratuitous polymorphism makes code much less readable and much costlier to maintain, usually for almost no gain.
One of the biggest strengths of Haskell is semantic clarity. You can often look at a Haskell expression, recognize its type, and then immediately understand exactly what the expression is doing. That is immensely valuable, not only for writing code, but for maintaining and refactoring it over the lifetime of an application, often by people other than the original author.
Adding polymorphism to code is semantically lossy. One of the biggest disasters I have ever suffered in software engineering was when someone went through an entire fairly large code base and changed it to use a more polymorphic Prelude, then left the company. Adding the polymorphism was mostly mechanical, but undoing it required hours upon hours of puzzling out the meaning of the code, line by line.
And do not relegate Richard's point #1 to CS 101 at university. Most software maintenance is done by the developers with the least Haskell experience. And that is the largest cost of software over time.
Polymorphism can be very powerful, of course, and there are a lot of great tools and techniques that use it in various ways. But why force some particular polymorphic generalization down everyone's throat when the cost of enabling it if you want it is essentially zero?
If you use a different Prelude in a large project, or in many small projects, take a few minutes to set up your dev environment accordingly.
As a case in point: Yesod uses many GHC extensions universally, among them NoImplicitPrelude. These are all listed in the automatically-generated default cabal file; they never need to be typed, and never appear in any source files. There is a single extra line in each file which sets up the whole environment:
import Import
You can bind that to an editor key if you'd like. You can write scripts. There are packages on Haskell which automate a lot of things. Need I go on with these trivialities?
A lot of thought went into making it easy to use GHC extensions. Advanced and experienced developers who need them should have no trouble at all using them, including alternative Preludes.
That is not to say that no changes should be made to the Prelude. Now that people are using a number of different alternative Preludes more regularly, I would hope we can use that experience to make much-needed improvements to the default Prelude. But the principal design considerations should be simplicity, ease of use even for beginners, and semantic clarity of code using it.
Thanks, Yitz _______________________________________________ Libraries mailing list Libraries@haskell.org http://www.haskell.org/mailman/listinfo/libraries
_______________________________________________ Libraries mailing list Libraries@haskell.org http://www.haskell.org/mailman/listinfo/libraries
_______________________________________________ Libraries mailing list Libraries@haskell.org http://www.haskell.org/mailman/listinfo/libraries

I think polymorphic code, subject to it "obeying laws/equations" is
generally a win. Fewer ways to have funny corner cases. :)
On Wed, Jun 18, 2014 at 12:00 PM, David Thomas
Of course, you can always add type annotations to be more specific about your types. And that actually might be clearer than having to remember all the various names for all the various monomorphic variants. Or it might not.
I think it's a pretty clear tradeoff: if you write 'map f xs' you know that 'xs' must be a list. If you write 'fmap f xs', you know only that 'xs' is a Functor. So you gain flexibility in when you can use 'fmap', but you lose the local information you get from the more constrained type of 'map'. The same argument applies when generalizing 'mapM' and friends. I'm still in favor of generalizing the Prelude functions to their Foldable/Traversable variants, but the downside is also clear to me.
This seems like a perfect problem for an IDE to solve, by the way.
Erik
On Wed, Jun 18, 2014 at 2:49 PM, Jake McArthur
wrote: I find this argument against polymorphism baffling. Do I really have to state the benefits of parametricity here? Probably not. Most likely,
is some specific style of polymorphism in mind going unsaid here, such as ListLike type classes that have tons of methods and don't really have any meaningful laws. Is this the case, or do you *really* mean to argue that polymorphism makes code confusing? If the latter, would you mind explaining why?
Please forgive me for any weird autocorrections, typos, or bad grammar. This was written on my phone, which is hard to write and proofread on.
Richard Eisenberg wrote:
Having lots of polymorphism in the Prelude is great, but for two
On Wed, Jun 18, 2014 at 6:06 AM, Erik Hesselink
wrote: there problems: 1) It's very confusing to novices. 2) In the case of using Control.Category definitions: kind-polymorphism is not portable
I wish to ignore (2) for now, as it's a smaller concern given that it affects only a portion of the proposed changes.
In my opinion, Richard missed the most important reason:
3) Gratuitous polymorphism makes code much less readable and much costlier to maintain, usually for almost no gain.
One of the biggest strengths of Haskell is semantic clarity. You can often look at a Haskell expression, recognize its type, and then immediately understand exactly what the expression is doing. That is immensely valuable, not only for writing code, but for maintaining and refactoring it over the lifetime of an application, often by people other than the original author.
Adding polymorphism to code is semantically lossy. One of the biggest disasters I have ever suffered in software engineering was when someone went through an entire fairly large code base and changed it to use a more polymorphic Prelude, then left the company. Adding the polymorphism was mostly mechanical, but undoing it required hours upon hours of puzzling out the meaning of the code, line by line.
And do not relegate Richard's point #1 to CS 101 at university. Most software maintenance is done by the developers with the least Haskell experience. And that is the largest cost of software over time.
Polymorphism can be very powerful, of course, and there are a lot of great tools and techniques that use it in various ways. But why force some particular polymorphic generalization down everyone's throat when the cost of enabling it if you want it is essentially zero?
If you use a different Prelude in a large project, or in many small projects, take a few minutes to set up your dev environment accordingly.
As a case in point: Yesod uses many GHC extensions universally, among them NoImplicitPrelude. These are all listed in the automatically-generated default cabal file; they never need to be typed, and never appear in any source files. There is a single extra line in each file which sets up the whole environment:
import Import
You can bind that to an editor key if you'd like. You can write scripts. There are packages on Haskell which automate a lot of things. Need I go on with these trivialities?
A lot of thought went into making it easy to use GHC extensions. Advanced and experienced developers who need them should have no trouble at all using them, including alternative Preludes.
That is not to say that no changes should be made to the Prelude. Now that people are using a number of different alternative Preludes more regularly, I would hope we can use that experience to make much-needed improvements to the default Prelude. But the principal design considerations should be simplicity, ease of use even for beginners, and semantic clarity of code using it.
Thanks, Yitz _______________________________________________ Libraries mailing list Libraries@haskell.org http://www.haskell.org/mailman/listinfo/libraries
_______________________________________________ Libraries mailing list Libraries@haskell.org http://www.haskell.org/mailman/listinfo/libraries
_______________________________________________ Libraries mailing list Libraries@haskell.org http://www.haskell.org/mailman/listinfo/libraries
Libraries mailing list Libraries@haskell.org http://www.haskell.org/mailman/listinfo/libraries

Polymorphic code is not always a win. When I see e.g. "x * x" it's very clear what's happening. But when someone instead uses "join (*) x"[1], it takes a while to piece together what's going on[2]. First you need to figure out what "join" is, and then you need to unify types: join :: Monad m => m (m a) -> m a (*) :: Num a => a -> a -> a I hate unifying types. That's what the compiler is for. I'm not against polymorphic functions, but it's not always a win. If your polymorphism is making a maintenance programmer invoke their mental type inferencer, you can expect a poor outcome. John [1] Why would anyone do that? What possible advantage does this form provide? Paid by the character? And yes, I've actually seen exactly this, I don't mean the slightly-more-defensible "join (*)" in a pipeline. [2] Unless you've already done this once and therefore are familiar with the idiom. On Wed, Jun 18, 2014 at 10:23 AM, Carter Schonwald < carter.schonwald@gmail.com> wrote:
I think polymorphic code, subject to it "obeying laws/equations" is generally a win. Fewer ways to have funny corner cases. :)
On Wed, Jun 18, 2014 at 12:00 PM, David Thomas
wrote: Of course, you can always add type annotations to be more specific about your types. And that actually might be clearer than having to remember all the various names for all the various monomorphic variants. Or it might not.
I think it's a pretty clear tradeoff: if you write 'map f xs' you know that 'xs' must be a list. If you write 'fmap f xs', you know only that 'xs' is a Functor. So you gain flexibility in when you can use 'fmap', but you lose the local information you get from the more constrained type of 'map'. The same argument applies when generalizing 'mapM' and friends. I'm still in favor of generalizing the Prelude functions to their Foldable/Traversable variants, but the downside is also clear to me.
This seems like a perfect problem for an IDE to solve, by the way.
Erik
On Wed, Jun 18, 2014 at 2:49 PM, Jake McArthur
wrote: I find this argument against polymorphism baffling. Do I really have to state the benefits of parametricity here? Probably not. Most likely,
is some specific style of polymorphism in mind going unsaid here, such as ListLike type classes that have tons of methods and don't really have any meaningful laws. Is this the case, or do you *really* mean to argue
polymorphism makes code confusing? If the latter, would you mind explaining why?
Please forgive me for any weird autocorrections, typos, or bad grammar. This was written on my phone, which is hard to write and proofread on.
Richard Eisenberg wrote:
Having lots of polymorphism in the Prelude is great, but for two
On Wed, Jun 18, 2014 at 6:06 AM, Erik Hesselink
wrote: there that problems: 1) It's very confusing to novices. 2) In the case of using Control.Category definitions: kind-polymorphism is not portable
I wish to ignore (2) for now, as it's a smaller concern given that it affects only a portion of the proposed changes.
In my opinion, Richard missed the most important reason:
3) Gratuitous polymorphism makes code much less readable and much costlier to maintain, usually for almost no gain.
One of the biggest strengths of Haskell is semantic clarity. You can often look at a Haskell expression, recognize its type, and then immediately understand exactly what the expression is doing. That is immensely valuable, not only for writing code, but for maintaining and refactoring it over the lifetime of an application, often by people other than the original author.
Adding polymorphism to code is semantically lossy. One of the biggest disasters I have ever suffered in software engineering was when someone went through an entire fairly large code base and changed it to use a more polymorphic Prelude, then left the company. Adding the polymorphism was mostly mechanical, but undoing it required hours upon hours of puzzling out the meaning of the code, line by line.
And do not relegate Richard's point #1 to CS 101 at university. Most software maintenance is done by the developers with the least Haskell experience. And that is the largest cost of software over time.
Polymorphism can be very powerful, of course, and there are a lot of great tools and techniques that use it in various ways. But why force some particular polymorphic generalization down everyone's throat when the cost of enabling it if you want it is essentially zero?
If you use a different Prelude in a large project, or in many small projects, take a few minutes to set up your dev environment accordingly.
As a case in point: Yesod uses many GHC extensions universally, among them NoImplicitPrelude. These are all listed in the automatically-generated default cabal file; they never need to be typed, and never appear in any source files. There is a single extra line in each file which sets up the whole environment:
import Import
You can bind that to an editor key if you'd like. You can write scripts. There are packages on Haskell which automate a lot of things. Need I go on with these trivialities?
A lot of thought went into making it easy to use GHC extensions. Advanced and experienced developers who need them should have no trouble at all using them, including alternative Preludes.
That is not to say that no changes should be made to the Prelude. Now that people are using a number of different alternative Preludes more regularly, I would hope we can use that experience to make much-needed improvements to the default Prelude. But the principal design considerations should be simplicity, ease of use even for beginners, and semantic clarity of code using it.
Thanks, Yitz _______________________________________________ Libraries mailing list Libraries@haskell.org http://www.haskell.org/mailman/listinfo/libraries
_______________________________________________ Libraries mailing list Libraries@haskell.org http://www.haskell.org/mailman/listinfo/libraries
_______________________________________________ Libraries mailing list Libraries@haskell.org http://www.haskell.org/mailman/listinfo/libraries
Libraries mailing list Libraries@haskell.org http://www.haskell.org/mailman/listinfo/libraries
_______________________________________________ Libraries mailing list Libraries@haskell.org http://www.haskell.org/mailman/listinfo/libraries

On 18 Jun 2014, at 12:09, Yitzchak Gale
Richard Eisenberg wrote:
Having lots of polymorphism in the Prelude is great, but for two problems: 1) It's very confusing to novices. 2) In the case of using Control.Category definitions: kind-polymorphism is not portable
I wish to ignore (2) for now, as it's a smaller concern given that it affects only a portion of the proposed changes.
In my opinion, Richard missed the most important reason:
3) Gratuitous polymorphism makes code much less readable and much costlier to maintain, usually for almost no gain.
The crucial problem for me would be: 4) Instance-based APIs are currently very difficult to discover. Just to name a few examples of useful but hidden functions: - looking at the Haddock for Data.Maybe, it is very hard to find: forM :: Monad m => Maybe a -> (a -> m b) -> m (Maybe b) - looking at the Haddock for Data.Either, it is *impossible* to discover: (+++) :: (a -> a') -> (b -> b') -> Either a b -> Either a’ b’ - looking at the Haddock for Data.Tuple, it is *impossible* to discover: (***) :: (a -> a’) -> (b -> b’) -> (a,b) -> (a’,b’) - looking at the Haddock for Data.Map , it is hard to spot: sequenceA_ :: Applicative f => Map a (f b) -> f () It helps if one knows in advance what Foldable, Traversable or Arrow are, but it is easier to understand a generalization if you were first exposed to concrete cases. So whenever we replace a concrete function by a typeclass-based generalization, we hurt the available documentation and make the learning curve even steeper. This is perhaps “just” a tooling problem that could be solved by haddock in some way, but until then it is my main concern with these proposals. Daniel

On 06/18/2014 09:04 PM, Daniel Gorín wrote:
On 18 Jun 2014, at 12:09, Yitzchak Gale
wrote: Richard Eisenberg wrote:
Having lots of polymorphism in the Prelude is great, but for two problems: 1) It's very confusing to novices. 2) In the case of using Control.Category definitions: kind-polymorphism is not portable
I wish to ignore (2) for now, as it's a smaller concern given that it affects only a portion of the proposed changes.
In my opinion, Richard missed the most important reason:
3) Gratuitous polymorphism makes code much less readable and much costlier to maintain, usually for almost no gain.
The crucial problem for me would be:
4) Instance-based APIs are currently very difficult to discover.
Just to name a few examples of useful but hidden functions:
- looking at the Haddock for Data.Maybe, it is very hard to find: forM :: Monad m => Maybe a -> (a -> m b) -> m (Maybe b)
- looking at the Haddock for Data.Either, it is *impossible* to discover: (+++) :: (a -> a') -> (b -> b') -> Either a b -> Either a’ b’
- looking at the Haddock for Data.Tuple, it is *impossible* to discover: (***) :: (a -> a’) -> (b -> b’) -> (a,b) -> (a’,b’)
- looking at the Haddock for Data.Map , it is hard to spot: sequenceA_ :: Applicative f => Map a (f b) -> f ()
It helps if one knows in advance what Foldable, Traversable or Arrow are, but it is easier to understand a generalization if you were first exposed to concrete cases. So whenever we replace a concrete function by a typeclass-based generalization, we hurt the available documentation and make the learning curve even steeper.
This is perhaps “just” a tooling problem that could be solved by haddock in some way, but until then it is my main concern with these proposals.
Regarding Haddock doing something: Do you have anything specific in mind here? At first I was just going to dismiss this as wishful thinking but perhaps we could actually do something about this. Maybe we could provide ‘alternative’ signatures which would make types more specific with some (which? all of known ones?) instances. Example: fmap :: Functor f => (a -> b) -> f a -> f b knowing that Maybe and [] and (Either c) are all instance of Functor, maybe there could be an option to show extra signatures such as fmap :: (a -> b) -> Maybe a -> Maybe b fmap :: (a -> b) -> [a] -> [b] fmap :: (a -> b) -> Either c a -> Either c b Is this what you had in mind? I thought lambdabot on IRC was able to do this but after asking around, it seems I was mistaken. I can certainly see its usefulness but it seems tricky to implement: Which instances to use? Should a user be able to say which instances should show in docs and if yes, how? How to implement this in the back-end? How should it look to the user? A something that is a stretch would be allowing the user to specify what ‘f’ was on the page and have it perform syntax substitution but that seems less useful: more user work and if they are going to do that then they might as well load it up into GHCi. If this isn't what you meant then I'd be interested to hear. A much easier way of course is to simply document some example instances. I think pipes does something like this as you can see at [1]. The downside of course is that it's not automated, has to be manually kept up to date and the implementer might not have thought about a particular instance you want to see. [1]: https://hackage.haskell.org/package/pipes-4.1.2/docs/Pipes.html#v:for
Daniel
_______________________________________________ Libraries mailing list Libraries@haskell.org http://www.haskell.org/mailman/listinfo/libraries
-- Mateusz K.

On Tue, Jun 24, 2014 at 3:42 AM, Mateusz Kowalczyk
Do you have anything specific in mind here? At first I was just going to dismiss this as wishful thinking but perhaps we could actually do something about this.
Maybe we could provide ‘alternative’ signatures which would make types more specific with some (which? all of known ones?) instances.
You can already see how that works out with Scala documentation, which is an incomprehensible mess.

On Tue, Jun 24, 2014 at 3:42 AM, Mateusz Kowalczyk
Do you have anything specific in mind here? At first I was just going to dismiss this as wishful thinking but perhaps we could actually do something about this.
Maybe we could provide ‘alternative’ signatures which would make types more specific with some (which? all of known ones?) instances.
One thing that might help is to list the specific type of methods below instance declarations, in a collapsible view to avoid cluttering. An example rendering (in "expanded view") would be:
[-] instance Functor ((->) r) where fmap :: (a -> b) -> (r -> a) -> (r -> b)
Non-methods, could be handled with documentation pragmas, so the library maintainer could pick which functions to document with specialized types. One could, for example, define Data.Either as:
module Data.Either ( … , (+++) )
where import Control.Arrow ( (+++) ) … {#- SPECIALIZE DOC (+++) :: (a -> a') -> (b -> b') -> Either a b -> Either a’ b’ #-} …
which would be rendered by haddock as, say:
(+++) :: (a -> a’) -> (b -> b’) -> Either a b -> Either a’ b’ Specialized signature of [Control.Arrow.(+++)]
with a suitable link. I’d prefer the module system being able to export more specific instances of functions, but this could be a decent compromise.
On 24 Jun 2014, at 18:20, Bryan O'Sullivan
You can already see how that works out with Scala documentation, which is an incomprehensible mess.
I’m not familiar with Scala documentation, do you think something like this would get messy?

On Jun 24, 2014, at 3:08 PM, Daniel Gorín
wrote: On Tue, Jun 24, 2014 at 3:42 AM, Mateusz Kowalczyk
wrote: Do you have anything specific in mind here? At first I was just going to dismiss this as wishful thinking but perhaps we could actually do something about this. Maybe we could provide ‘alternative’ signatures which would make types more specific with some (which? all of known ones?) instances.
One thing that might help is to list the specific type of methods below instance declarations, in a collapsible view to avoid cluttering. An example rendering (in "expanded view") would be:
[-] instance Functor ((->) r) where fmap :: (a -> b) -> (r -> a) -> (r -> b)
Being able to "open" an instance line in haddock to see what it means could be quite useful. It'd likely require a fair bit of work in haddock though as it'd have to synthesize that information somehow.

On 06/25/2014 01:10 AM, Edward Kmett wrote:
On Jun 24, 2014, at 3:08 PM, Daniel Gorín
wrote: On Tue, Jun 24, 2014 at 3:42 AM, Mateusz Kowalczyk
wrote: Do you have anything specific in mind here? At first I was just going to dismiss this as wishful thinking but perhaps we could actually do something about this. Maybe we could provide ‘alternative’ signatures which would make types more specific with some (which? all of known ones?) instances.
One thing that might help is to list the specific type of methods below instance declarations, in a collapsible view to avoid cluttering. An example rendering (in "expanded view") would be:
[-] instance Functor ((->) r) where fmap :: (a -> b) -> (r -> a) -> (r -> b)
Being able to "open" an instance line in haddock to see what it means could be quite useful. It'd likely require a fair bit of work in haddock though as it'd have to synthesize that information somehow.
I think that it might not be very hard to get this information from GHC for regular typeclasses although it might be harder for TFs &c. I think presentation is a big problem here and the rest is just figuring out how to use the GHC API to spit out what we need. -- Mateusz K.

On 06/24/2014 06:20 PM, Bryan O'Sullivan wrote:
On Tue, Jun 24, 2014 at 3:42 AM, Mateusz Kowalczyk
wrote: Do you have anything specific in mind here? At first I was just going to dismiss this as wishful thinking but perhaps we could actually do something about this.
Maybe we could provide ‘alternative’ signatures which would make types more specific with some (which? all of known ones?) instances.
You can already see how that works out with Scala documentation, which is an incomprehensible mess.
Can you link to a specific example? I looked up the API docs but I have no idea what I should be looking for here. I think that expandable instance lines would be the best without getting in the way as they won't use up any new space which would let us avoid clutter. If we generate this info automagically then there is no clutter in the source itself either. -- Mateusz K.

Just to add my 2ct that it definitely don't work well for Scala.
That being said, it should be possible to have some nice UI/UX to help
investigate such things... but the approach Scala documentation is using is
definitely not ideal.
On 24 June 2014 17:20, Bryan O'Sullivan
On Tue, Jun 24, 2014 at 3:42 AM, Mateusz Kowalczyk < fuuzetsu@fuuzetsu.co.uk> wrote:
Do you have anything specific in mind here? At first I was just going to dismiss this as wishful thinking but perhaps we could actually do something about this.
Maybe we could provide ‘alternative’ signatures which would make types more specific with some (which? all of known ones?) instances.
You can already see how that works out with Scala documentation, which is an incomprehensible mess.
_______________________________________________ Libraries mailing list Libraries@haskell.org http://www.haskell.org/mailman/listinfo/libraries
-- *A\ois* http://twitter.com/aloiscochard http://github.com/aloiscochard

On Tue, Jun 24, 2014 at 6:42 AM, Mateusz Kowalczyk
If this isn't what you meant then I'd be interested to hear. A much easier way of course is to simply document some example instances. I think pipes does something like this as you can see at [1]. The downside of course is that it's not automated, has to be manually kept up to date and the implementer might not have thought about a particular instance you want to see.
[1]: https://hackage.haskell.org/package/pipes-4.1.2/docs/Pipes.html#v:for
As far as keeping things "manually up to date", it is possible to use doctest to show and confirm things like:
let f x y = (x :: Int) + y :t f f :: Int -> Int -> Int
But different ghc versions print types differently (type variable names change, constraints come out in a different order, etc.), so keeping the output up-to-date might be the same effort as manually checking type signatures like the ones in the Pipes documentation.

Am 18.06.2014 um 12:09 schrieb Yitzchak Gale:
In my opinion, Richard missed the most important reason:
3) Gratuitous polymorphism makes code much less readable and much costlier to maintain, usually for almost no gain.
One of the biggest strengths of Haskell is semantic clarity. You can often look at a Haskell expression, recognize its type, and then immediately understand exactly what the expression is doing. That is immensely valuable, not only for writing code, but for maintaining and refactoring it over the lifetime of an application, often by people other than the original author.
I have to strongly agree. I have already written things like fmap (fmap (fmap (fmap f))) and find it hard to find out later, which fmap refers to Maybe, which one to List, and which one to Map. That is, I prefer 'map' even if there is an 'fmap'.

On 10/08/14 20:26, Henning Thielemann wrote:
I have to strongly agree. I have already written things like
fmap (fmap (fmap (fmap f)))
and find it hard to find out later, which fmap refers to Maybe, which one to List, and which one to Map. That is, I prefer 'map' even if there is an 'fmap'.
But this problem comes up /anywhere/ you are composing polymorphic functions. Just renaming functions in the case of `fmap` just solves that particular problem, but doesn't solve the problem in the general case. I think this is a problem that is truly solved best by editor tools. You, the editor, need to know the type of some expression to continue coding, so you should be able to ask your editor such a question. Even if you can't do that now, I'm fairly convinced that you will be able to in the future, so I don't think such problems should be solved with code modifications - they simply don't scale (what about mapMaybe? mapEither? mapIO?) - ocharles

Am 11.08.2014 um 12:24 schrieb Oliver Charles:
On 10/08/14 20:26, Henning Thielemann wrote:
I have to strongly agree. I have already written things like
fmap (fmap (fmap (fmap f)))
and find it hard to find out later, which fmap refers to Maybe, which one to List, and which one to Map. That is, I prefer 'map' even if there is an 'fmap'.
But this problem comes up /anywhere/ you are composing polymorphic functions. Just renaming functions in the case of `fmap` just solves that particular problem, but doesn't solve the problem in the general case. I think this is a problem that is truly solved best by editor tools.
I'd prefer to be able to read such code without the help of an editor. E.g. map (Map.map (Maybe.map (map f))) makes everything obvious without any tool.

Why not just explicitly annotate the types?
Tom
El Aug 11, 2014, a las 7:12, Henning Thielemann
Am 11.08.2014 um 12:24 schrieb Oliver Charles:
On 10/08/14 20:26, Henning Thielemann wrote:
I have to strongly agree. I have already written things like
fmap (fmap (fmap (fmap f)))
and find it hard to find out later, which fmap refers to Maybe, which one to List, and which one to Map. That is, I prefer 'map' even if there is an 'fmap'.
But this problem comes up /anywhere/ you are composing polymorphic functions. Just renaming functions in the case of `fmap` just solves that particular problem, but doesn't solve the problem in the general case. I think this is a problem that is truly solved best by editor tools.
I'd prefer to be able to read such code without the help of an editor. E.g.
map (Map.map (Maybe.map (map f)))
makes everything obvious without any tool.
_______________________________________________ Libraries mailing list Libraries@haskell.org http://www.haskell.org/mailman/listinfo/libraries

Am 11.08.2014 um 18:03 schrieb amindfv@gmail.com:
El Aug 11, 2014, a las 7:12, Henning Thielemann
escribió: I'd prefer to be able to read such code without the help of an editor. E.g.
map (Map.map (Maybe.map (map f)))
makes everything obvious without any tool.
Why not just explicitly annotate the types?
First, the type annotation becomes quite cumbersome if the second argument of 'map' is not explicitly written and second, I think it is the wrong way round to select a function via types when I can already name the selected function.
participants (19)
-
adam vogt
-
Alois Cochard
-
amindfv@gmail.com
-
Bryan O'Sullivan
-
Carter Schonwald
-
Daniel Gorín
-
David Thomas
-
Edward Kmett
-
Erik Hesselink
-
Greg Weber
-
Henning Thielemann
-
Herbert Valerio Riedel
-
Jake McArthur
-
John Lato
-
Mateusz Kowalczyk
-
Oliver Charles
-
Richard Eisenberg
-
Tom Ellis
-
Yitzchak Gale