Reputation: 51
I' ve tried the example from http://www.haskell.org/haskellwiki/GHC.Generics#A_generic_function
that is:
import GHC.Generics
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE DefaultSignaturesGeneric #-}
data Bin = O | I deriving Show
data UserTree a = Node a (UserTree a) (UserTree a) | Leaf deriving Generic
class GSerialize f where
gput :: f a -> [Bin]
instance GSerialize U1 where
gput U1 = []
instance (GSerialize a, GSerialize b) => GSerialize (a :*: b) where
gput (x :*: y) = gput x ++ gput y
instance (GSerialize a, GSerialize b) => GSerialize (a :+: b) where
gput (L1 x) = O : gput x
gput (R1 x) = I : gput x
instance (GSerialize a) => GSerialize (M1 i c a) where
gput (M1 x) = gput x
instance (Serialize a) => GSerialize (K1 i a) where
gput (K1 x) = put x
class Serialize a where
put :: a -> [Bin]
default put :: (Generic a, GSerialize (Rep a)) => a -> [Bin]
put = gput . from
instance Serialize Int
instance Serialize Char
instance Serialize Bool
instance (Serialize a) => Serialize (UserTree a)
toserialize :: (Serialize (UserTree a) ) => UserTree a -> [Bin]
toserialize tree = put tree
I tested the function with the call:
toserialize Leaf
here the compiler gives an error-message:
Ambiguous type variable `a0' in the constraint:
(Serialize a0) arising from a use of `toserialize'
Probable fix: add a type signature that fixes these type variable(s)
In the expression: serialize Leaf
In an equation for `it': it = toserialize Leaf
What is missing here?
Upvotes: 2
Views: 192
Reputation: 24802
The problem is that since the type variable a
in UserTree a
doesn't appear at all in the Leaf
constructor, GHC cannot determine which a
you want for your value. You can fix this by adding an explicit type signature such as
toserialize (Leaf :: UserTree Int)
UPDATE: The example toserialize (Node 2 Leaf Leaf)
hangs because the generic representation for Int
is recursive
type Rep Int = D1 D_Int (C1 C_Int (S1 NoSelector (Rec0 Int)))
For "primitive" types which don't have "normal" constructors, you usually have to define instances by hand. However, since for example Bool
is simply
data Bool = True | False
This works with the generic Serialize
instance
toserialize (Node True Leaf Leaf)
Upvotes: 2