我有一些编译的代码:
{-# 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
类型。
答案 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,而且必须将它们复制到任何地方都有点烦人,但确实可以完成工作。