Haskell 具有更高类型的GADT类型推理
我有一些代码可以编译:Haskell 具有更高类型的GADT类型推理,haskell,ghc,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
{-# 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 ""
{-# 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 ""
在我的真实代码中,我需要的关键是说服GHC,如果y
的类型是Foo(cmzp)
,而x
的类型是cmzp'
,那么c'~c
和m'~m
。上面的代码实现了这一点,因为我能够调用g
我想用两种正交的方式修改这段代码,但我似乎不知道如何让GHC用这两种修改来编译代码
第一个更改:添加-XPolyKinds
。GHC 7.8.3投诉:
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 ""
我得到了类似的错误(无法推断(c1~c)
,无法推断(m1~m)
)。
datatypes
似乎与此相关:如果我限制m
使用kindConstraint
而不是kindBar
,则代码可以很好地编译
我给出了两个如何破坏原始代码的示例,这两个示例都使用了更高级的类型。我尝试过使用case语句而不是模式保护,尝试过给
节点指定类型而不是x
,我通常的技巧在这里不起作用
我并不挑剔x
的类型在哪里结束/它看起来是什么样子,我只需要说服GHC,如果y
的类型是Foo(cmzp)
,那么x
的类型是cmzp'
对于一些不相关的类型zp'
,我将原来的问题大大简化为如下:,不使用{-#LANGUAGE polyteches}
编译,但使用polyteches
编译失败
{-# 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
这个错误强烈地表明了我已经怀疑的,答案取决于是否。若多类类型的应用程序是内射的,我们可以推导出如下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 -}
,但ghc不知道。为了让ghc推断类型应用程序是内射的,我们需要提供种类签名,以便编译器知道种类是等价的
我还没有找到足够的注释来解释这个问题的原始、过于简化的版本。当简化处理类型的问题时,将类型简化为本质上的代理
有时是过度的,因为这样可以减少附加类型签名的位置。你必须解决一个更有意义的问题。这个问题可以通过添加种类签名来解决
例如,当使用-XPolyKinds
时,编译以下代码:
{-# 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 ""
{-# 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
上的kind签名:
{-# 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 ""
我不知道为什么我需要更多的SIG用于数据类型
,而且必须到处复制它们有点烦人,但它确实完成了工作。在您为x
和y
提供的类型签名中,zp
和zp'
是完全不相关的类型。您在函数的类型签名中提到了zp
,但在其他地方没有提到zp'
。你怎么能指望编译器推断出它们之间的关系?@user2407038我不知道。我只希望c
和m
是相同的。g
的存根在f
中无法使用提供的类型。它在f
中与g::astfdom(cma)->astfdom(cmb)->astfdom(cmb)
一起工作。g
的类型可疑地与f
的类型相似;它不能让我相信有任何有趣的函数需要这个证明。我问了一个关于类型相等的问题,它意味着种类相等。不,x
的类型不是编写我给出的玩具代码所必需的,但它是编写我真正想要的代码所必需的。我为一个函数g
添加了存根,希望能解决您的问题。“这正是它声称无法推断的…”不完全是。如果更改discard
以返回x
的代理,则它是相同的。您的代码将y
的类型与自身匹配。我正在尝试匹配x
和y
中的类型。