
#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 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. 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.) 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. Sorry, @muesli4, I didn't mean to steal your thunder here! I hope you don't mind the debate. :) Thoughts (anyone) on this alternative? -- Ticket URL: http://ghc.haskell.org/trac/ghc/ticket/9883#comment:6 GHC http://www.haskell.org/ghc/ The Glasgow Haskell Compiler