Make OverloadedLists more usable by splitting the class interface
Problem
While the OverloadedLists extension is very useful, it limits the types which can be used with it, by requesting too much. Assume you have a database specific DSEL which allows you to use list-like expressions in queries, it's easy to implement fromList
, but we are unable to implement toList
in a reasonable fashion without a backend and an existing connection.
Proposal
Modify the class interface in a way that does not require the instance to be listable.
class IsList l where
type Item l
fromList :: [Item l] -> l
fromListN :: Int -> [Item l] -> l
We could then provide the pattern matching functionality on IsList
instances with different approaches.
Another class
Just add another class which is used to provide the toList
function, used on pattern matches. This is the easiest approach
class AsList l where
type Item l
toList :: l -> [Item l]
Desugaring works as usual and it goes well with all structures. (The name is not the best though.)
Using Data.Foldable
The list pattern gets desugared using Data.Foldable:
f :: (IsList l, Foldable l) => l -> l
f [x, y, z] = [x, y]
f l = l
gets something like:
import Data.Foldable (toList)
f :: (IsList l, Foldable l) => l -> l
f (toList -> [x, y, z]) = fromList [x, y]
f l = l
This approach does not go well with structures like Data.Map
, because it expects the type constructor to take the element type as first argument, but we would like to have a tuple type. Maybe a wrapper could be provided, but I think it's not the way to go, as long as Data.Foldable does not use type families.
Drawbacks
Both approaches complicate the type of list expressions. This requires a bit more of typing, but it specifies exactly which functionality you need and one can simply drop the unused one, without creating dangerous dummy implementations:
-
IsList
for overloaded list expressions -
AsList
orFoldable
for pattern matching Most of the time OverloadedLists is used for convenience, so I don't expect the normal user to be really affected, library writers, specifically those who write some kind of DSEL, will have to be more precise, but get a more type-safe approach, which can not fail at runtime.
Trac metadata
Trac field | Value |
---|---|
Version | 7.8.3 |
Type | FeatureRequest |
TypeOfFailure | OtherFailure |
Priority | normal |
Resolution | Unresolved |
Component | External Core |
Test case | |
Differential revisions | |
BlockedBy | |
Related | |
Blocking | |
CC | |
Operating system | |
Architecture |