用GHC.TypeLits玩弄我制作了这段代码
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)
如果我尝试使用此错误调用af,则无法编译:
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"))
仍然适用于instance SingI a => AC (A a)
,很明显它是类型同义词的东西,但我找不到任何解释。很高兴听到它为什么会这样,并且有没有机会添加一些标签之王来输入同义词?
扩展,用于编译:
DataKinds,
KindSignatures,
TypeSynonymInstances,
ScopedTypeVariables,
-- MultiParamTypeClasses,
UndecidableInstances
答案 0 :(得分:1)
来自GHC用户指南的7.6.3.1. Relaxed rules for the instance head部分:
使用-XTypeSynonymInstances标志,实例头可以使用类型同义词。与往常一样,使用类型同义词是只是写入类型同义词定义的RHS 的简写。
将此规则应用于您的实例声明会导致:
instance (SingI a, SingI b, SingI c) => AC (A a) where
af = (fromSing (sing :: Sing c), A)
请注意,这与您为“A”编写的实例相同,但在c
和b
上有约束,现在甚至不会出现在实例头中。当您尝试使用实例时:
print $ fst $ (af :: (String, B "a" "b" "c"))
转变为
print $ fst $ (af :: (String, A "a"))
编译器抱怨没有instance for SingI Symbol c
,因为它不知道c
是什么。要编译此代码,您必须提供一个instance SingI (c :: Symbol)
,它对所有c 起作用(您可以使用FlexibleInstances
编写这样的实例,但它不会是很有用,因为你无法根据c
做出选择。如果您不想要此行为,则可以使用newtype。