toying around with GHC.TypeLits I made this code
data A (a :: Symbol) = A
type B a (b :: Symbol) (c :: Symbol) = A a
class AC a where
af :: (String, a)
-- instance SingI a => AC (A a) where
-- af = (fromSing (sing :: Sing a), A)
instance (SingI a, SingI b, SingI c) => AC (B a b c) where
af = (fromSing (sing :: Sing c), A)
Which fails to compile if I try to call af somewhere with this error:
No instance for (SingI Symbol c) arising from a use of `af'
Possible fix: add an instance declaration for (SingI Symbol c)
In the second argument of `($)', namely
`(af :: (String, B "a" "b" "c"))'
In the second argument of `($)', namely
`fst $ (af :: (String, B "a" "b" "c"))'
In a stmt of a 'do' block:
print $ fst $ (af :: (String, B "a" "b" "c"))
Still it works fine for instance SingI a => AC (A a)
it's clear that it's something with type synonym, but I can't find any explanation of this. Would be glad to hear why it works like this, and is there any chance to add some king of tag to type synonym?
Extension, used to compile:
DataKinds,
KindSignatures,
TypeSynonymInstances,
ScopedTypeVariables,
-- MultiParamTypeClasses,
UndecidableInstances
From the GHC User Guide, section 7.6.3.1. Relaxed rules for the instance head :
With the -XTypeSynonymInstances flag, instance heads may use type synonyms. As always, using a type synonym is just shorthand for writing the RHS of the type synonym definition.
Applying this rule to your instance declaration leads to:
instance (SingI a, SingI b, SingI c) => AC (A a) where
af = (fromSing (sing :: Sing c), A)
Note that this is equal to the instance you wrote for 'A', but with constraints on c
and b
, which now don't even appear in the instance head. When you try to use the instance:
print $ fst $ (af :: (String, B "a" "b" "c"))
That gets transformed to
print $ fst $ (af :: (String, A "a"))
And the compiler complains that there is no instance for SingI Symbol c
, because it doesn't know what c
is. To make this code compile, you'd have to provide an instance SingI (c :: Symbol)
that works for all c (you can write such an instance with FlexibleInstances
, but it's not going to be useful because you can't make a choice depending on c
). If you don't want this behaviour, you could use a newtype.
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.