什么是f
?
class C f where
comp :: f b c -> f a b -> f a c
我写道:(* -> *) -> * -> *
这是对的吗? c
是一种混凝土型*
。 a
是一种采用类型并生成类型的类型。这两个都是f
的参数?我的论证是否正确?
什么是T
?
data T f g = T (f String Int) (g Bool)
f
有两种具体类型作为参数(String
和Int
)。 g
有一个参数(Bool
)这两个参数都是T
的参数。所以我有:(*->*->*)->(*->*)->*
。它是否正确?谢谢
GHCi可以告诉你各种各样的事情。例如,如果你把:
data T f g = T (f String Int) (g Bool)
在文件Kinds.hs
中,您可以将其加载到GHCi并询问T
的种类:
> :l Kinds.hs
> :k T
T :: (* -> * -> *) -> (* -> *) -> *
>
所以看起来GHCi同意你的解决方案。
对于你的第一个问题,你不能要求GHCi直接告诉你f
的种类,但由于f
是类型类C
的参数,你可以要求C
的种类:
> :k C
C :: (* -> * -> *) -> Constraint
>
意思是C
采用一种类型的* -> * -> *
来产生约束。因此,GHCi不同意你的观点,并认为f
是善良的* -> * -> *
。
查看类型签名:
comp :: f b c -> f a b -> f a c
请注意,你不能有f
(* -> *) -> * -> *
,因为f b c
意味着b
是善良的* -> *
,而f a b
意味着b
的善良*
,它不能两者兼而有之。
事实证明,最普遍的可能是:
f :: k -> k -> *
前两个参数被迫拥有相同类型k
,因为b
用于两个位置(分别在f a b
和f b c
),最终结果被迫有类*
因为f b c
,f a b
和f a c
都需要具体类型,以便comp
的类型签名有意义。
然而,Haskell98(没有扩展)并没有推断出最普遍的可能类型,因此它选择k
为*
,给出类型签名* -> * -> *
。事实证明,如果你启用某个扩展(PolyKinds
),那么种类签名将是k -> k -> *
。
对于第一个问题,我不明白你为什么认为a
有善意的* -> *
。根据所写的,a
只是一个*
,仅此而已。因此,f
的种类是* -> * -> *
。
对于第二个问题,你是对的。