Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/haskell/8.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Haskell 类型解构_Haskell_Types_Type Constructor - Fatal编程技术网

Haskell 类型解构

Haskell 类型解构,haskell,types,type-constructor,Haskell,Types,Type Constructor,我的数据类型将始终至少有两个参数,最后两个参数始终分别为“q”和“m”: {-# LANGUAGE TypeFamilies, FlexibleContexts, UndecidableInstances, TypeOperators, DataKinds, ConstraintKinds, FlexibleInstances #-} data D1 q m = D1 q data D2 t q m = D2 q class Foo a where -- a has kind * ->

我的数据类型将始终至少有两个参数,最后两个参数始终分别为“q”和“m”:

{-# LANGUAGE TypeFamilies, FlexibleContexts, UndecidableInstances, TypeOperators, DataKinds, ConstraintKinds, FlexibleInstances #-}

data D1 q m = D1 q
data D2 t q m = D2 q

class Foo a where -- a has kind * -> *
   f :: a x -> a x

class (Foo b) => Bar b where -- b has kind * -> *
   -- the purpose of g is to change ONE type parameter, while fixing the rest
   -- the intent of the equality constraints is to decompose the parameter b into
   -- its base type and 'q' parameter, then use the same base type with a *different*
   -- `q` parameter for the answer
   g :: (b ~ bBase q1, b' ~ bBase q2) => b m -> b' m

instance (Foo (D2 t q), Integral q) => Bar (D2 t q) where
   g (D2 q) = D2 $ fromIntegral q -- LINE 1
此程序导致错误

Could not deduce (bBase ~ D2 t0) (LINE 1)
当我编写这个实例时,我当然打算
bBase~d2t
。我猜t是不受约束的(因此引入了t0),我不知道GHC是否能够解构这种类型。或者我只是在做些傻事

更重要的是,如果我将Bar的参数设置为kind*->*->*,那么这种类型相等/类型解构就没有必要了。但是我无法强制执行Foo约束:

class (Foo (b q)) => Bar b where -- b has kind * -> * -> *
  g :: b q m -> q b' -- this signature is now quite simple, and I would have no problem implementing it
这不会起作用,因为q不是Bar的参数,我不希望它成为Bar的参数

我找到了一个使用两个额外的“虚拟”关联类型的解决方案,但如果我不需要它们,我真的不喜欢它们:

class (Foo b, b ~ (BBase b) (BMod b)) => Bar b where -- b has kind * -> *
  type BBase b :: * -> * -> *
  type BMod b :: *

  g :: (Qux (BMod b), Qux q') => b m -> (BBase b) q' m

instance (Foo (D2 t q), Integral q) => Bar (D2 t q) where
  type BBase (D2 t q) = D2 t
  type BMod (D2 t q) = q

  g (D2 q) = D2 $ fromIntegral q
这是可行的,但它相当于显式地解构类型,鉴于实例的简单类型,我认为这应该是不必要的

我正在寻找这两种方法的解决方案:告诉我如何在“更适用的”类型上实施类约束,或者告诉我如何使GHC解构类型


谢谢

根据您的描述,您有类型
b'::*->*->*
,您希望对其约束应用的
b't::*->*
(适用于所有
t

在总结时,您需要解构一个类型,这是您在这里的尝试 从a
b开始::*->*
假定为某个类型的结果 应用程序
b=b't
,或者对“更适用的”类型强制执行约束 从a
b'::*->*->*
的起点开始

解构类型是不可能的,因为编译器甚至不知道
b
是否是“可解构的”。事实上,它可能不是,例如,我可以使一个实例
实例栏可能
,但
可能
不能被解构为一个类型
b'::*->*->*->*
和一些类型
t:*

相反,从类型
b'::*->*->*
开始,可以将
b'
应用程序上的约束移动到类的主体中,其中变量被量化:

  class Bar (b :: * -> * -> *) where
      g :: (Foo (b q1), Foo (b q2)) => b q1 m -> b q2 m
例如,还有一个问题:q1和q2可能有自己的约束, e、 g.对于
D2
实例,您需要
Integral
约束。但是,
Bar
修复了所有实例的
q1
q2
上的约束(在本例中为空约束)。解决方案是使用“约束类类型族”,它允许实例指定自己的约束:

  class Bar (b :: * -> * -> *) where
      type Constr b t :: Constraint
      g :: (Foo (b q1), Foo (b q2), Constr b q1, Constr b q2) => b q1 m -> b q2 m
(包括
{-#语言约束种类{-}
和导入
GHC.Prim

然后您可以编写
D2
实例:

   instance Bar (D2 t) where
      type Constr (D2 t) q = Integral q
      g (D2 q) = D2 $ fromIntegral q

检查类方法时,我得到的完整错误消息是
amy16.hs:7:1:非法等式约束b~bBase q1(使用-XGADTs或-XTypeFamilies允许此操作):g::forall(bBase::*->*->*)q1(b'::*->*)q2 m。(b~bBase q1,b'~bBase q2)=>bm->bm在
Bar'的类声明中失败,加载的模块:无。因此我认为您需要添加
GADTs
语言pragma或
TypeFamilies
pragma,我在上面的代码中没有包含编译标志/语言pragma,但我当然使用了这些术语中所需的一切(这应该可以使所有代码片段都工作):类型族、FlexibleContext、不可判定实例、类型运算符、数据种类、Constraint种类、FlexibleInstances