Polymorphism in the Prelude

John Lato jwlato at gmail.com
Fri Jun 20 00:46:38 UTC 2014


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 at 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 <davidleothomas at gmail.com>
> 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.
>>
>> On Wed, Jun 18, 2014 at 6:06 AM, Erik Hesselink <hesselink at gmail.com>
>> wrote:
>> > 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 <jake.mcarthur at gmail.com>
>> 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 at haskell.org
>> >> http://www.haskell.org/mailman/listinfo/libraries
>> >>
>> >> _______________________________________________
>> >> Libraries mailing list
>> >> Libraries at haskell.org
>> >> http://www.haskell.org/mailman/listinfo/libraries
>> >>
>> > _______________________________________________
>> > Libraries mailing list
>> > Libraries at haskell.org
>> > http://www.haskell.org/mailman/listinfo/libraries
>> _______________________________________________
>> Libraries mailing list
>> Libraries at haskell.org
>> http://www.haskell.org/mailman/listinfo/libraries
>>
>
>
> _______________________________________________
> Libraries mailing list
> Libraries at haskell.org
> http://www.haskell.org/mailman/listinfo/libraries
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://www.haskell.org/pipermail/libraries/attachments/20140619/02f47a18/attachment.html>


More information about the Libraries mailing list