这个编译代码是this code的最小化示例,来自this issue的回答,带有syntactic-2.0。我还在Data.Type.Equality中使用了从sameNat
派生的sameModType
定义。
我一直在使用这个解决方案没有问题,但我想使模数q
具有类型多态性,其具体目标是使Proxy (nat :: Nat)
只为nat :: Nat
(虽然仍然能够使用类型*
的模数)。
{-# LANGUAGE GADTs,
MultiParamTypeClasses,
FunctionalDependencies,
FlexibleContexts,
FlexibleInstances,
TypeOperators,
ScopedTypeVariables,
DataKinds,
KindSignatures #-}
import Data.Tagged
import Data.Proxy
import Data.Type.Equality
import Data.Constraint
import Unsafe.Coerce
import GHC.TypeLits
newtype Zq q i = Zq i
data ZqType q
where
ZqType :: (Modulus q Int) => Proxy q -> ZqType (Zq q Int)
class (Integral i) => Modulus a i | a -> i where
value :: Tagged a i
instance (KnownNat q) => Modulus (Proxy (q :: Nat)) Int where
value = Tagged $ fromIntegral $ natVal (Proxy :: Proxy q)
sameModType :: (Modulus p i, Modulus q i)
=> Proxy p -> Proxy q -> Maybe (p :~: q)
sameModType p q | (proxy value p) == (proxy value q) =
Just $ unsafeCoerce Refl
| otherwise = Nothing
typeEqSym :: ZqType p -> ZqType q -> Maybe (Dict (p ~ q))
typeEqSym (ZqType p) (ZqType q) = do
Refl <- sameModType p q -- LINE 39
return Dict -- LINE 40
但是当我在上面的代码中添加-XPolyKinds
扩展名时,我得到了几个编译错误:
Foo.hs:39:36:
Could not deduce (k1 ~ k)
...
Expected type: Proxy q0
Actual type: Proxy q2
Relevant bindings include
q :: Proxy q2 (bound at Foo.hs:38:30)
p :: Proxy q1 (bound at Foo.hs:38:19)
In the second argument of ‘sameFactoredType’, namely ‘q’
In a stmt of a 'do' block: Refl <- sameFactoredType p q
Foo.hs:40:16:
Could not deduce (k ~ k1)
...
Relevant bindings include
q :: Proxy q2 (bound at Foo.hs:38:30)
p :: Proxy q1 (bound at Foo.hs:38:19)
In the first argument of ‘return’, namely ‘Dict’
In a stmt of a 'do' block: return Dict
In the expression:
do { Refl <- sameFactoredType p q;
return Dict }
Foo.hs:40:16:
Could not deduce (q1 ~ q2)
...
Relevant bindings include
q :: Proxy q2 (bound at Foo.hs:38:30)
p :: Proxy q1 (bound at Foo.hs:38:19)
In the first argument of ‘return’, namely ‘Dict’
In a stmt of a 'do' block: return Dict
In the expression:
do { Refl <- sameFactoredType p q;
return Dict }
我不太了解类型相等的魔法,知道如何解决这个问题。似乎大多数问题在能够强制执行GHC所要求的约束方面都无可救药地超出范围,但我在PolyKinds
之前从未遇到过这类问题。需要更改什么才能使用PolyKinds
编译代码?
答案 0 :(得分:5)
我可以解释这个问题,但由于我不完全确定你想做什么,我不确定你怎么能最好地解决它。
问题在于ZqType
:
data ZqType q
where
ZqType :: (Modulus q Int) => Proxy q -> ZqType (Zq q Int)
ZqType
的类型参数称为q
,这有点误导。这是一个GADT,类型参数与构造函数中出现的类型参数无关。我更喜欢给出一种亲切的签名。 ZqType
是什么类型的?好吧,Zq q Int
是一种数据类型,所以它有类*
。您已将ZqType
应用于Zq q Int
,因此ZqType
的类型为* -> *
(尽管PolyKind
s)。所以我们有
data ZqType :: * -> * where
ZqType :: (Modulus q Int) => Proxy q -> ZqType (Zq q Int)
接下来,让我们看一下ZqType
构造函数的类型是什么?没有多种类型,它是你写下来的:
ZqType :: (Modulus q Int) => Proxy q -> ZqType (Zq q Int)
但是对于PolyKind
s,q
仅出现在种类多态位置,因此会变为:
ZqType :: forall (q :: k). (Modulus q Int) => Proxy q -> ZqType (Zq q Int)
现在让我们看看你如何在sameModType
中使用它:
typeEqSym :: ZqType a -> ZqType b -> Maybe (Dict (a ~ b))
typeEqSym (ZqType p) (ZqType q) = do
...
我已重命名类型变量以避免混淆。因此,a
是未知类型*
,而b
是另一种未知类型*
。您在GADT上进行模式匹配。目前,GHC得知a
实际为Zq q1 Int
某些未知类q1
的{{1}} k1
。此外,GHC了解b
实际上Zq q2 Int
是某种未知类型q2
的某些未知k2
。特别是,我们在此不知道k1
和k2
是相同的,因为这是强制执行的。
然后你继续调用sameModType
,它要求两个代理都属于同一类,导致你的第一个错误。剩下的错误都是同样问题的结果。
答案 1 :(得分:3)
我不知道这是否是您正在寻找的内容,但您可以简单地公开基础论点的类型以供日后使用:
data ZqType q k where
ZqType :: Modulus q Int => Proxy (q :: k) -> ZqType (Zq q Int) ('KProxy :: KProxy k)
typeEqSym :: ZqType p k -> ZqType q k -> Maybe (Dict (p ~ q))
typeEqSym (ZqType p) (ZqType q) = do
Refl <- sameModType p q
return Dict
instance Modulus Int Int where
instance Modulus (n :: Nat) Int where
KProxy
应该在Data.Proxy
,但它只是data KProxy (x :: *) = KProxy
。
受挫的例子:
>let x = ZqType (Proxy :: Proxy (10 :: Nat))
>let y = ZqType (Proxy :: Proxy Int)
>typeEqSym x y
<interactive>:25:13:
Couldn't match kind `*' with `Nat'
Expected type: ZqType (Zq Int Int) 'KProxy
Actual type: ZqType (Zq Int Int) 'KProxy
In the second argument of `typeEqSym', namely `y'
In the expression: typeEqSym x y