Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/haskell/10.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_Typeclass - Fatal编程技术网

类型约束中的逻辑蕴涵(Haskell)

类型约束中的逻辑蕴涵(Haskell),haskell,typeclass,Haskell,Typeclass,我如何表达容器满足某些“透明度属性”的想法?例如,考虑容器类型 v,这样显示暗示“代码>显示(V A)< /代码>。 用例是,我希望有一个函数,在这个函数中,被调用方决定使用哪个容器,但保证容器在许多类型类约束方面表现良好 下面是一个(非工作)示例,说明我的想法: mapUnknown :: (forall v. (Functor v, (forall n. Num n => Num (v n)) => v b -> a)) -> [b] -

我如何表达容器满足某些“透明度属性”的想法?例如,考虑容器类型<代码> v<代码>,这样<代码>显示暗示“代码>显示(V A)< /代码>。 用例是,我希望有一个函数,在这个函数中,被调用方决定使用哪个容器,但保证容器在许多类型类约束方面表现良好

下面是一个(非工作)示例,说明我的想法:

mapUnknown :: (forall v. (Functor v, (forall n. Num n => Num (v n)) => v b -> a)) 
              -> [b] -> [a]
其思想是传入一个函数,该函数必须能够处理任何容器类型
v
。可以保证
v
是一个
Functor
,并且
Num b
意味着
Num(vb)
。如果传入的
b
不是
Num
,则忽略该规则

这可能吗

注:

以下操作不起作用:

class Container c a where
  foo :: c a -> [a]

instance forall a c. (Container c a, Show a) => Show (c a) where
  show _ = "whatever"

f :: (Container c a, Show a) => c a -> String
f as =
  show as

这是因为我们可以定义一个实例
容器va
,也可以
显示(va)
。然后,GHC无法确定是使用
Container
定义的
show
还是使用
show(va)
定义的show。我们不想定义一个新的
show
函数,我们只想在知道容器的类型后断言它存在。

好吧,如果我理解正确,您想创建一个类,比如说
NumToNum
,这样,编译器就可以从两个实例
Num v
Num n
中推断出
Num(v n)
存在一个实例。以下是您如何完成此任务的方法

这里的关键是创建一个类型,比如说,
NumI::*->*
,这样就不会有任何类型的值
numin
,除非
n
属于
Num
类。严格地说,这是不可能的,因为Haskell的任何类型都有人居住(至少有
(| |
)。但是,如果您避免显式地将实现方法标记为
未定义的
,并深入研究深层递归,那么这样做会相对安全:

data NumI n where NumI :: Num n => NumI n
因此,如果
n
不属于
Num
类,则仍然存在
Num n
类型的
undefined
,但没有太多其他值

当然,您需要
GADTs
扩展

现在,可以这样定义上述类:

class NumToNum v where numToNum :: Num n => NumI (v n)
有了它,您可以通过模式匹配获得
Num(vn)
实例:

case (numToNum :: NumI (v n)) of NumI => do_something
这里的
do\u something
已经知道
Num(vn)
实例,这要感谢构造函数
NumI
的类型签名

声明
NumToNum
类的实例很容易,您只需说

data V n = -- whatever
instance Num n => Num (V n) where -- some implementation
instance NumToNum V where numToNum = NumI

能否创建一个名为Container的类型类,然后将所有容器数据类型注册为该类型类的实例?然后,您可以代替
mapnknown
执行
mapContainer
,该函数将是
Container
类型类所需的函数。请参见编辑--它不起作用。您尝试执行的操作将不起作用,因为
forall n。Num n=>Num(v n)
不是有效的约束。但是,使用,可以将所需的约束具体化为类型为
forall n的函数。Num n:-Num(v n)
。您的函数的完整类型可以是
(对于所有n.Num n:-Num(vn))->(vb->a)->[b]->[a]
——但我不知道您实际希望它做什么。如果启用了
OverlappingInstances
,则第二个示例可以工作。抱歉,我还没有完全理解。如果我有一个函数签名
(Applicative v,NumToNum v)=>v String->()
编译器会自动意识到我创建的任何
v Double
都是
Num
s吗?或者我必须将所有内容包装在模式匹配中以强制实现它吗?来自
数据的
:-
约束在这里有用吗?是的,您必须在任何地方使用模式匹配。是的,
:-
似乎是一条路要走;我只是教你怎么自己做。