Haskell 统一与类约束相关联的类型同义词
我有一个嵌套类型,希望使用关联的类型同义词部分指定该类型。下面是一些非常精简的代码,演示了该问题:Haskell 统一与类约束相关联的类型同义词,haskell,type-families,Haskell,Type Families,我有一个嵌套类型,希望使用关联的类型同义词部分指定该类型。下面是一些非常精简的代码,演示了该问题: {-# LANGUAGE TypeFamilies, FlexibleInstances, FlexibleContexts, MultiParamTypeClasses #-} f :: Int -> Int f x = x+1 data X t i newtype Z i = Z i deriving (Eq,Show) newtype Y q = Y (T q) class Qu
{-# LANGUAGE TypeFamilies,
FlexibleInstances,
FlexibleContexts,
MultiParamTypeClasses #-}
f :: Int -> Int
f x = x+1
data X t i
newtype Z i = Z i deriving (Eq,Show)
newtype Y q = Y (T q)
class Qux m r where
g :: (T m) -> r
class (Integral (T a)) => Foo a where
type T a
-- ... functions
instance (Integral i) => Foo (X (Z i) i) where
type T (X (Z i) i) = i
instance (Foo q) => Num (Y q) -- where ...
instance (Foo q, Foo (X m' Int)) => Qux (X m' Int) (Y q) where
g x = fromIntegral $ f $ x
哪种情况(即使是不可判定的实例)会导致编译器错误:
Could not deduce (T (X m' Int) ~ Int)
我知道将此约束添加到Qux实例会使编译器感到高兴。但是,我知道在我的程序中(T(X arg1 arg2))=arg2,所以我试图找出如何不必须编写此约束
instance Foo (X (Z i) i) where type T (X (Z i) i) = Z i
instance Foo (X (Z' i) i) where type T (X (Z' i) i) = Z' i
我的问题是:我能让Haskell意识到,当我将'Int'作为X的第二个参数时,这与同义词T(xa'Int)是一样的吗?我意识到我在使用有关实例外观的“特殊”知识,但我认为应该有一种方法将其传达给编译器
谢谢因为我还不确定我是否理解这个问题,我将讨论您编写的代码;也许我的漫谈会为你指明一个有用的方向,或者引发一些我可以回答的尖锐问题。也就是说:警告!漫无边际的回答 首先,让我们谈谈
Bar
类
-- class (i ~ S b) => Bar b i where
-- type S b
-- ...
既然我们知道约束条件i~sb
,我们不妨放弃i
参数,我将在接下来的讨论中这样做
class Bar b where type S b
-- or, if the class is empty, just
-- type family S b
-- with no class declaration at all
下面是这个新类的实例的外观:
instance Bar (Z i) where type S (Z i) = i
instance Bar (Z' i) where type S (Z' i) = i
如果对于任何类型的构造函数来说都是这样的话,你可以考虑把这个写为一个实例,而不是:
-- instance Bar (f i) where type S (f i) = i
现在,让我们谈谈Foo
类。要将其更改为与上述内容相匹配,我们将
class Bar (T a) => Foo a where type T a
您已经声明了两个实例:
-- instance (Bar (Z i) i) => Foo (X (Z i) i) where
-- type T (X (Z i) i) = Z i
--
-- instance (Bar (Z' i) i) => Foo (X' (Z' i) i) where
-- type T (X (Z' i) i) = Z' i
我们可以像以前一样将第二个参数剥离到Bar
,但我们还可以做另一件事:因为我们知道有一个Bar(zi)
实例(我们在上面声明了它!),所以我们可以去掉实例约束
instance Foo (X (Z i) i) where type T (X (Z i) i) = Z i
instance Foo (X (Z' i) i) where type T (X (Z' i) i) = Z' i
是否将i
参数保留为X
取决于X
应该表示什么。到目前为止,我们还没有更改任何类声明或数据类型的语义,只是更改了它们的声明和实例化方式。更改X
可能不具有相同的属性;很难说没有看到X
的定义。有了数据声明和足够多的扩展,上面的前奏曲就完成了
现在,您的投诉:
- 您说以下内容无法编译:
但是,对于class Qux a instance Foo (X a' Int) => Qux (X a' Int) instance Foo (X' a' Int) => Qux (X' a' Int)
,它确实在这里编译。它需要不可判定的实例
:没有什么可以阻止某人稍后出现并声明这样的实例不可判定的实例
instance Qux (X Y Int) => Foo (X Y Int) Then, checking whether `Qux (X Y Int)` had an instance would require checking whether `Foo (X Y Int)` had an instance and vice versa. Loop.
- 您会说,“它还需要实例约束
,尽管我知道在我的程序中,它们总是同义词。”。我不知道第一个“it”是什么——我不能重现这个错误——所以我不能很好地回答这个问题。另外,正如我以前抱怨的那样,这个约束是不恰当的:S(T(xa'))~Int
,因此X:(*->*)->*->*->*
,而xa':*->*
需要一个T
类型的参数。所以我假设你的意思是*
尽管有这些抱怨,我们仍然可以问,为什么从我们目前的假设来看,S(T(xa'Int))~Int
是不可证明的。到目前为止,我们只为符合模式S(T(xa'Int))~Int
和X(zi)i
的类型声明了X(zi)i
实例。因此,类型函数Foo
只能在其参数类型符合其中一种模式时减少。类型T
不太适合这两种模式。我们可以把它塞进正确的模式:我们可以试着用xa'Int
来代替(比如)。然后我们会发现X(zint)Int
,因此T(X(Z Int)Int)~Z Int
这回答了如何修复类型级别的缩减,但没有解释如何修复任何没有生成的代码。为此,我们必须找出类型检查器为什么需要从S(T(X(Z Int)Int)~S(Z Int)~Int
到S(t(xa'Int))
,并看看我们是否能说服它,像Int
,或者,使用上面建议的广义S(t(X(Z Int))这样的更具体(且令人满意)的强制Int)~Int
实例,Bar
。如果没有足够的代码重现错误,我们当然无法帮助您S(T(X(f Int)Int)~Int
- 你会问,“我能让Haskell意识到当我把'Int'作为X的第二个参数时,这与同义词S(T(xa'Int))是一样的吗?”。我根本不理解这个问题。你想要一个可证明的等式
?这就是我从你的问题的字面解读中得到的解释 在上下文中,我想你可能想问你是否能得到一个可证明的等式xaint~S(T(xa'Int))
;在这种情况下,答案是“肯定!”。我们将滥用我们在上面知道的b~S(T(xab))
的事实,把这个等式化为更强的b~S(zb)
。然后我们可以将上面的zb~T(xab)
实例替换为一个进行此声明的实例,仅此而已:Foo
或者,我们可以假设另一个合理的方程,instance Foo (X a b) where T (X a b) = Z b
;然后,为了证明T(xab)~a
,我们只需要证明S(T(xab))~b
(通过减少sa~b
),我们就可以编写另一个T
实例:Foo
instance (Bar a, S a ~ b) => Foo (X a b) where T (X a b) = a
Qux
类声明?什么是“以相同方式嵌套的其他Foo实例”意思?什么是“根据X生成多个实例,但对于generiz Z和固定嵌套类型I”意思?此外,您提出的许多约束看起来不太好