[GHC] #9883: Make OverloadedLists more usable by splitting the class interface

GHC ghc-devs at haskell.org
Tue Dec 16 12:52:06 UTC 2014


#9883: Make OverloadedLists more usable by splitting the class interface
-------------------------------------+-------------------------------------
              Reporter:  muesli4     |            Owner:
                  Type:  feature     |           Status:  new
  request                            |        Milestone:  ⊥
              Priority:  normal      |          Version:  7.8.3
             Component:  External    |         Keywords:  overloaded lists,
  Core                               |  islist
            Resolution:              |     Architecture:  Unknown/Multiple
      Operating System:              |       Difficulty:  Moderate (less
  Unknown/Multiple                   |  than a day)
       Type of failure:              |       Blocked By:  7495
  None/Unknown                       |  Related Tickets:  #7495
             Test Case:              |
              Blocking:              |
Differential Revisions:              |
-------------------------------------+-------------------------------------

Comment (by muesli4):

 Replying to [comment:6 goldfire]:
 > Maybe I'm missing something basic, but why do we need classes at all
 here? I propose we just desugar the list to use some functions in scope,
 and if they don't type-check, that's the programmer's problem.
 This sounds like something, which should be done with the RebindableSyntax
 extension. Type classes are useful, because other libraries can easily
 provide instances for it, without them you have to provide them via some
 third party library and it seems to me that other uses are more like a
 corner case. But of course I may be wrong, so I am all for usability and
 convenience, without excluding special cases (as I said, these could be
 introduced with the RebindableSyntax extension).
 >
 > Concretely, here are the 7 expression forms from OverloadedLists, and my
 proposal for what they desugar to:
 >
 > {{{
 > []          -- buildList 0 (listStart `listSep` listEnd)
 > [x]         -- buildList 1 (listStart `listSep` x `listSep` listEnd)
 > [x,y,z]     -- buildList 3 (listStart `listSep` x `listSep` y `listSep`
 z `listSep` listEnd)
 > [x .. ]     -- enumFrom x
 > [x,y ..]    -- enumFromThen x y
 > [x .. y]    -- enumFromTo x y
 > [x,y .. z]  -- enumFromThenTo x y z
 > }}}
 >
 > The `enumXXX` functions would use whatever is in scope -- not
 necessarily the methods from `Enum`.
 >
 > For regular old lists, we get
 >
 > {{{
 > buildList _ (_:elts) = elts
 > listStart = undefined
 > listSep = (:)
 > infixr 5 `listSep`
 > listEnd = []
 > }}}
 >
 > and the `enumXXX` functions are indeed taken from the `Enum` class.
 >
 > Note that I included the fixity declaration for `listSep` above --
 there's no reason to disallow a ''left''-associative separator. (Though,
 all the elements in the list would effectively be wrapped in parentheses;
 the precedence level of the `listSep` fixity declaration is meaningless in
 the desugaring.)

 I like what you could achieve with it, but I don't like how you do it:
   * The use of {{{undefined}}} seems like a hack to make the types work.
   * Can you provide some use cases where different associativity is an
 advantage?
   * I don't like to use operator syntax here.
   * Are you able to give definitions for these functions, such that we
 could use the list syntax for different types in the same module?
     Let's say heterogenous lists (was that the intention?) and normal
 lists.

 > To me, this seems maximally flexible.
 >
 > With pattern synonyms, we could mimc this behavior in patterns.
 >
 > {{{
 > []          -- MatchList 0 (ListStart `ListSep` ListEnd)
 > [x]         -- MatchList 1 (ListStart `ListSep` x `ListSep` ListEnd)
 > [x,y,z]     -- MatchList 3 (ListStart `ListSep` x `ListSep` y `ListSep`
 z `ListSep` ListEnd)
 > }}}
 >
 > For regular old lists, we get
 >
 > {{{
 > pattern MatchList n l <- ((\list -> (length list, undefined:list)) ->
 (n, l))
 > pattern ListStart <- _
 > pattern ListSep h t = h : t
 > infixr 5 `ListSep`
 > pattern ListEnd = []
 > }}}
 >
 > The construction for `MatchList` is painful. Improvements here are
 welcome.
 Can you use different types with the same pattern? The compiler should
 know the length of the list, so maybe it can be expressed with a type
 literal (though I have no idea how to do that).
 > Sorry, @muesli4, I didn't mean to steal your thunder here! I hope you
 don't mind the debate. :)
 Of course, that was the reason I started the ticket. I appreciate your
 contribution, but I think it goes a bit over the top, my proposal was just
 a slight change in an already existing extension. And I don't know whether
 you can provide the same functionality, which currently exists.

--
Ticket URL: <http://ghc.haskell.org/trac/ghc/ticket/9883#comment:9>
GHC <http://www.haskell.org/ghc/>
The Glasgow Haskell Compiler


More information about the ghc-tickets mailing list