具有更高结合类型的GADT类型推断

时间:2015-01-16 03:56:38

标签: haskell ghc

我有一些编译的代码:

{-# LANGUAGE ScopedTypeVariables, KindSignatures, GADTs, 
             FlexibleContexts #-}

module Foo where

data Foo :: (* -> *) where
  Foo :: c m zp' -> Foo (c m zp)

f :: forall c m zp d . Foo (c m zp) -> d
f y@(Foo (x :: c m a)) = g x y

g :: c m a -> Foo (c m b) -> d
g = error ""

我在实际代码中需要的关键是要说服GHC,如果y类型为Foo (c m zp)x类型为c' m' zp',那么{{1 }和c' ~ c。上面的代码实现了这一点,因为我可以调用m' ~ m

我想以两种正交方式更改此代码,但我似乎无法弄清楚如何使GHC编译代码并进行任何更改。

首先更改:添加g。 GHC 7.8.3抱怨:

-XPolyKinds

第二次改变:忘掉Foo.hs:10:11: Could not deduce ((~) (k2 -> k3 -> *) c1 c) from the context ((~) * (c m zp) (c1 m1 zp1)) bound by a pattern with constructor Foo :: forall (k :: BOX) (k :: BOX) (c :: k -> k -> *) (m :: k) (zp' :: k) (zp :: k). c m zp' -> Foo (c m zp), in an equation for ‘f’ at Foo.hs:10:6-21 ‘c1’ is a rigid type variable bound by a pattern with constructor Foo :: forall (k :: BOX) (k :: BOX) (c :: k -> k -> *) (m :: k) (zp' :: k) (zp :: k). c m zp' -> Foo (c m zp), in an equation for ‘f’ at Foo.hs:10:6 ‘c’ is a rigid type variable bound by the type signature for f :: Foo (c m zp) -> d at Foo.hs:9:13 Expected type: c1 m1 zp' Actual type: c m a Relevant bindings include y :: Foo (c m zp) (bound at Foo.hs:10:3) f :: Foo (c m zp) -> d (bound at Foo.hs:10:1) In the pattern: x :: c m a In the pattern: Foo (x :: c m a) In an equation for ‘f’: f y@(Foo (x :: c m a)) = g x y Foo.hs:10:11: Could not deduce ((~) k2 m1 m) from the context ((~) * (c m zp) (c1 m1 zp1)) ... 。相反,我想使用-XPolyKinds创建新类型并限制-XDataKinds的种类:

m

我收到了类似的错误({-# LANGUAGE ScopedTypeVariables, KindSignatures, GADTs, FlexibleContexts, DataKinds #-} module Foo where data Bar data Foo :: (* -> *) where Foo :: c (m :: Bar) zp' -> Foo (c m zp) f :: forall c m zp d . Foo (c m zp) -> d f y@(Foo (x :: c m a)) = g x y g :: c m a -> Foo (c m b) -> d g = error "" can't deduce (c1 ~ c))。 can't deduce (m1 ~ m)似乎与此相关:如果我限制DataKinds使用m而不是种类Constraint,则代码编译正常。


我已经举了两个如何打破原始代码的例子,这两个例子都使用了更高级的类型。我尝试使用案例陈述而不是模式保护,我尝试过给Bar代替node的类型,我通常的伎俩都不在这里工作。

我并不挑剔x的类型最终/看起来如何,我只需要能够说服GHC,如果x的类型为{{1} }},然后y对于某些不相关的类型Foo (c m zp)具有x类型。

2 个答案:

答案 0 :(得分:2)

我将原始问题大大简化为以下问题,编译时没有{-# LANGUAGE PolyKinds #-}但无法使用PolyKinds进行编译。

{-# LANGUAGE ScopedTypeVariables, KindSignatures, GADTs #-}
{-# LANGUAGE PolyKinds #-}

data Pair1 :: (* -> *) where
  Pair1 :: Pair1 (c a, c b)

data D p a where
    D :: p (a, b) -> D p a -> D p b

f :: forall c z. D Pair1 (c z) -> D Pair1 (c z)
f y@(D Pair1 x) |
    (_ :: D Pair1 (c z)) <- y,
    (_ :: D Pair1 (c z')) <- x = y

启用PolyKinds时,编译器错误为

Could not deduce (c1 ~ c)
from the context ((a, c z) ~ (c1 a1, c1 b))

这个错误强烈暗示我已经怀疑的,答案取决于polykinded type application is injective。如果多金属类型应用是单射的,我们可以推导出c1 ~ c如下。

(a,   c z) ~ (c1 a1,   c1 b)
(a,) (c z) ~ (c1 a1,) (c1 b) {- switch to prefix notation -}
      c z  ~           c1 b  {- f a ~ g b implies a ~ b -}
      c    ~           c1    {- f a ~ g b implies f ~ g -}
      c1   ~           c     {- ~ is reflexive -}

Polykinded type application is injective,但ghc不知道。为了让ghc推断类型应用程序是单射的,我们需要提供类型签名,以便编译器知道这些类型是等价的。

我没有为您原来的,过度简化的问题版本找到足够的注释。在简化问题类型时,将类型简化为Proxy有时会过多,因为它会减少附加类型签名的位置。您有found places to attach kind signatures更有意义的问题。

答案 1 :(得分:1)

可以通过添加种类签名解决问题。

例如,使用-XPolyKinds时,以下代码将编译:

{-# LANGUAGE ScopedTypeVariables, KindSignatures, GADTs, 
             FlexibleContexts, PolyKinds #-}

module Foo where

data Foo :: (* -> *) where
  Foo :: (c :: k -> * -> *) m zp' -> Foo (c m zp)

f :: forall (c :: k -> * -> *) m zp d . Foo (c m zp) -> d
f y@(Foo x) = g x y

g :: c m a -> Foo (c m b) -> d
g = error ""

对于-XDataKinds版本,我还需要在g上签名:

{-# LANGUAGE ScopedTypeVariables, KindSignatures, GADTs, 
             FlexibleContexts, DataKinds #-}

module Foo where

data Bar

data Foo :: (* -> *) where
  Foo :: (c :: Bar -> * -> *) m zp' -> Foo (c m zp)

f :: forall (c :: Bar -> * -> *) m zp d . Foo (c m zp) -> d
f y@(Foo x) = g x y

g :: forall (c :: Bar -> * -> *) m a b d . c m a -> Foo (c m b) -> d
g = error ""

我不确定为什么我需要为DataKinds添加更多sigs,而且必须将它们复制到任何地方都有点烦人,但确实可以完成工作。