将Type.Equality与PolyKinds一起使用

时间:2014-05-20 15:49:13

标签: haskell ghc higher-kinded-types

这个编译代码是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编译代码?

2 个答案:

答案 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。特别是,我们在此不知道k1k2是相同的,因为这是强制执行的。

然后你继续调用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