Given the following class:
class ListIsomorphic l where
toList :: l a -> [a]
fromList :: [a] -> l a
How can I write a instance for vector types using Data.Vector.Generic
? This doesn't work:
instance (V.Vector v a) => ListIsomorphic v where
toList = V.toList
fromList = V.fromList
Giving me:
test.hs:31:10:
Variable ‘a’ occurs more often than in the instance head
in the constraint: V.Vector v a
(Use UndecidableInstances to permit this)
In the instance declaration for ‘ListIsomorphic v’
Don't. Adding an instance for all
v
to yourListable
class will become cumbersome to use due to overlapping instances.A
Vector v a => v
isn't isomorphic to a list because it is constrained by which items can be elements of the list. You'd need a class that captures this constraint, something likeInstead of adding
ConstrainedList
instances for all typesVector v a => v
which would get us into overlapping instances territory, instead we'll define it only for the types we're interested in. The following will cover all the types with aVector
instance in the vector package.Instances for other types
You can write a
ConstrainedList
instance for regular lists[]
that requires only the empty constraint for its elements.Anywhere that uses
toList
orfromList
will also require anElem l a
instance.When we know concrete types for the lists and elements these functions will be easy to use without messing around with constraints.
Here Be Dragons
Don't try what follows. If you are interested in the class of things that are isomorphic to lists without additional constraints, just make another class for it. This just demonstrates what you can do when you've designed yourself into a corner: summon a dragon.
You can also write functions that require a proof that there is no constraint on the elements of a
ConstrainedList
. This is way off into the realms of theconstraints
package and programming styles that aren't really supported by GHC, but there aren't enoughconstraints
examples so I'll leave this one here.We could check that a
ConstrainedList
has no constraint by just checking thatElem l a ~ ()
, but that wouldn't work if its constraint was written in a different way.()
isn't the same type asAny a
even though()
impliesAny a
. The constraints package captures relationships like this by reifying them to the type classesClass
and:=>
All of that work lets us easily reuse functions without providing all those dictionaries when a concrete list type is known.
I frequently run into this problem. Here are two solutions I've come up with:
Change the class parameters:
Use constraint kinds