1

Since it seems that writing a ListIsomorphic instance for generic vectors is impossible (or not a good idea), I'm trying to write one for Vector.Unboxed directly.

class ListIsomorphic l where
    toList    :: l a -> [a]
    fromList  :: [a] -> l a

instance ListIsomorphic UV.Vector where
    toList   = UV.toList
    fromList = UV.fromList

I'm getting the following error:

test.hs:70:14:
    No instance for (UV.Unbox a) arising from a use of ‘UV.toList’
    Possible fix:
    add (UV.Unbox a) to the context of
        the type signature for toList :: UV.Vector a -> [a]
    In the expression: UV.toList
    In an equation for ‘toList’: toList = UV.toList
    In the instance declaration for ‘ListIsomorphic UV.Vector’

test.hs:71:16:
    No instance for (UV.Unbox a) arising from a use of ‘UV.fromList’
    Possible fix:
    add (UV.Unbox a) to the context of
        the type signature for fromList :: [a] -> UV.Vector a
    In the expression: UV.fromList
    In an equation for ‘fromList’: fromList = UV.fromList
    In the instance declaration for ‘ListIsomorphic UV.Vector’

I've tried following the compiler error advice but it didn't work. How can I write it?

Community
  • 1
  • 1
MaiaVictor
  • 51,090
  • 44
  • 144
  • 286
  • That basically just means you can't define this instance. An instance method can't have stricter requirements on its arguments than those given in the class definition. – Cubic Aug 21 '15 at 03:13

1 Answers1

2

You can't. Your ListIsomorphic class promises that fromList can be applied to any type a. However, the unboxed vector requires that a is an instance of Unbox.

You could instead write a class ListIsomorphicUnboxed that has:

class ListIsomorphicUnboxed l where
    fromListUnboxed :: (Unbox a) => [a] -> l a
    toListUnboxed :: (Unbox a) => l a -> [a]

An alternate approach could be to use Constraints (you'll need to add a few language extensions):

{-# LANGUAGE ConstraintKinds, TypeFamilies #-}
import GHC.Exts (Constraint)

class ListIsomorphic l where
    type C l a :: Constraint
    type C l a = () -- default to no constraint

    fromList :: C l a => [a] -> l a
    toList :: C l a => l a -> [a]

instance ListIsomorphic UV.Vector where
    type C UV.Vector a = UV.Unbox a
    toList   = UV.toList
    fromList = UV.fromList

(Code untested!)

In this way each instance can have different constraints. This isn't a very common solution, however.

porges
  • 30,133
  • 4
  • 83
  • 114
  • Is there any way to abbreviate the `(ListIsomorphic l, Elem l a)` constraint? – MaiaVictor Aug 21 '15 at 03:53
  • Yes, with `ConstraintKinds` you can write `type ListLike l a = (ListIsomorphic l, Elem l a)`. Then use it like `someFunc :: (ListLike l a) => l a -> ...` – porges Aug 21 '15 at 04:00
  • Okay, sorry for the rain of related questions. It seems like I finally managed to get it to work now. Just let me know if this is a bad practice and is likely to break things later? – MaiaVictor Aug 21 '15 at 04:02
  • @Viclib I don't know of any common complaints about this pattern. – Daniel Wagner Aug 21 '15 at 05:48