Given that I have the data types
data A a = A a
data B b = B b
and the type class
class C c where
f :: c a -> a
Now the class C expects a type of kind * -> *
, so I can do
instance C A where
f (A a) = a
instance C B where
f (B b) = b
Now given a function such as:
ab :: b -> A (B b)
ab = A . B
How would I declare an instance of C
for the result type?
I first through I might be able to use a type synonym with TypeSynonymInstances
, like this:
type AB b = A (B b)
class C AB where
f (A (B b)) = b
Especially since ghci reports the correct kind:
*Main> :k AB
AB :: * -> *
However, you can't seem to use partially applied type synonyms in instance declarations (or anywhere, for that matter).
Is there some way I can compose the types A
and B
like I can compose the constructors, or some other syntax for declaring an instance for such a nested type?
The simplest is probably to define
newtype AB a = AB { unAB :: A (B a) }
GHC should be able to derive a C instance for this.
You could also use TypeCompose to accomplish this,
type AB = A :. B
instance C AB where
f = f . f . unO
There is no way to declare such an instance. In fact, allowing arbitrary type functions such as AB
in instance declarations makes instance resolution undecidable.
Usually, the solution is to declare a newtype. Of course, you will have to explicitly convert to and from the newtype when you want to use the class.
newtype AB a = AB (A (B a))
instance C AB where f (AB (A (B a)) = a
If your usage of the class is simple enough, you may want to just pass the overloaded method as a parameter of functions that use it.
You have to use a newtype
. A type synonym must always be applied completely, as it is only a synonym, not a lambda. A newtype
has no runtime penalty; it will be removed when compiling.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.