Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/visual-studio-2010/4.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,我有一个第一个typeclass,它接受……ofleaf的列表列表: {-# LANGUAGE MultiParamTypeClasses, FlexibleInstances, UndecidableInstances #-} class ListTree leaf t where lmap :: (leaf -> leaf) -> t -> t instance ListTree leaf leaf where lmap f v = f v instance ListT

我有一个第一个typeclass,它接受……of
leaf
的列表列表:

{-# LANGUAGE MultiParamTypeClasses, FlexibleInstances, UndecidableInstances #-}
class ListTree leaf t where
  lmap :: (leaf -> leaf) -> t -> t
instance ListTree leaf leaf where lmap f v = f v
instance ListTree leaf t => ListTree leaf [t] where lmap f v = map (lmap f) v
我有第二个typeclass,它接受
a
的2元组和3元组:

class Tups a t where
  tmap :: (a -> a) -> t -> t
instance Tups a (a,a) where tmap f (x,y) = (f x, f y)
instance Tups a (a,a,a) where tmap f (x,y,z) = (f x, f y, f z)
我想结合它们来描述以2或3元组结尾的嵌套列表,这些元组属于
leaf
类型:

class LTTree leaf t where
  ltmap :: (a -> a) -> t -> t
instance (Tups leaf x, ListTree x t) => LTTree leaf t where ltmap f v = lmap (tmap f) v
但是,最后一段代码给了我几个错误:

Could not deduce (LTTree leaf0 t)
  from the context: LTTree leaf t

In the ambiguity check for ‘ltmap’
  To defer the ambiguity check to use sites, enable AllowAmbiguousTypes

Could not deduce (Tups leaf x0)
  from the context: (Tups leaf x, ListTree x t)

In the ambiguity check for an instance declaration
  To defer the ambiguity check to use sites, enable AllowAmbiguousTypes
  In the instance declaration for ‘LTTree leaf t’
如果我添加
AllowAmbiguousTypes
,我仍然会得到类似的错误

通过内联其他两个TypeClass的代码,我可以很好地定义
LTTree
类,不过:

class LTTree leaf t where
  ltmap :: (leaf -> leaf) -> t -> t
instance LTTree leaf (leaf,leaf) where ltmap f (x,y) = (f x, f y)
instance LTTree leaf (leaf,leaf,leaf) where ltmap f (x,y,z) = (f x, f y, f z)
instance LTTree leaf t => LTTree leaf [t] where ltmap f v = map (ltmap f)
如何将
列表树叶t
类与
Tups a t
类结合起来,使列表树的叶是
a
的2或3元组?
如果可以的话,我不介意添加额外的GHC扩展


如果重要的话,我真正的用例是为列表树建模,其中叶子是行多态记录(使用CTRex),其中记录中的每个字段都是某个typeclass的实例(例如,
Show
,以打印树)。

您还有另一个问题。你的
列表树
类没用

> lmap id [5 :: Integer]
error: blah blah
> lmap id (5 :: Integer)
error: blah blah
> lmap (+2) [[5::Integer], [], [2,3]]
error: blah blah
先添加一些黑魔法来解决这个问题:

{-# LANGUAGE FunctionalDependencies, GADTs #-}
class ListTree leaf tree where lmap :: (leaf -> leaf) -> (tree -> tree)
instance {-# OVERLAPPABLE #-} (leaf ~ tree) => ListTree leaf tree where -- 1
  lmap = id
instance ListTree leaf tree => ListTree leaf [tree] where -- 2
  lmap = map . lmap
(a~b)
是一个等式约束;当
a
b
是同一类型时,它保持不变。它需要使用
GADTs
TypeFamilies

根据,当检查
lmap id[5::Integer]
时,GHC会遇到这两个实例,并发现它们都可以被实例化:
1
带有
leaf=[Integer]
tree=[Integer]
2
带有
leaf=Integer
tree=[Integer]
。要选择一个,它将检查
2
的实例化是否对
1
有效。也就是说:
leaf=Integer
tree=[Integer]
是否是
1
的有效实例化?答案是肯定的,因为带有等式约束的上下文直到稍后才会被检查。然后,它检查
可重叠的
/
重叠
/
重叠
杂注<如果有更好的实例,代码>可重叠的实例将被丢弃。在这种情况下,
1
被丢弃,只剩下
2
。它被使用,所以
lmap id[5::Integer]==[5]
。其他例子也适用

LTTree
中,您有一个输入错误。应该是:

class LTTree leaf tree where ltmap :: (leaf -> leaf) -> tree -> tree
使用
leaf
,而不是
a
。你还有一个问题:推理机对你非常生气,因为你让它做了所有这些工作:

> instance (Tups leaf x, ListTree x t) => LTTree leaf t where ltmap f v = lmap (tmap f) v
error: blah blah
启用
ScopedTypeVariables
TypeApplications
以帮助它:

{-# LANGUAGE ScopedTypeVariables, TypeApplications #-}
instance (Tups leaf x, ListTree x t) => LTTree leaf t where ltmap f v = lmap @x @t (tmap @leaf @x f) v
(或者用
显式地给出类型,但这很痛苦)

但更好的办法是启用
功能依赖性
,并开始四处传播,因为它们代表了类型级计算的理念:typeclass的某些参数子集可以唯一地决定其他参数。这将生成最终版本:

{-# LANGUAGE FlexibleInstances
           , FunctionalDependencies
           , GADTs
           , UndecidableInstances #-}
class ListTree leaf tree | tree -> leaf where lmap :: (leaf -> leaf) -> tree -> tree
instance {-# OVERLAPPABLE #-} (leaf ~ tree) => ListTree leaf tree where lmap = id
instance ListTree leaf tree => ListTree leaf [tree] where lmap = map . lmap
-- The tree determines the leaf

class Tups leaf tree | tree -> leaf where tmap :: (leaf -> leaf) -> tree -> tree
-- Change instances to help type inference along:
instance (a ~ b) => Tups a (a, b) where tmap f (x, y) = (f x, f y)
instance (a ~ b, b ~ c) => Tups a (a, b, c) where tmap f (x, y, z) = (f x, f y, f z)
-- tmap (+2) (5 :: Integer, 3, 2) now works because the type info from 5 spreads out
-- via the equality constraints

class LTTree leaf tree | tree -> leaf where ltmap :: (leaf -> leaf) -> tree -> tree
instance (Tups leaf mid, ListTree mid tree) => LTTree leaf tree where ltmap = lmap . tmap
-- mid can be deduced from tree via ListTree's fundep
-- leaf can be deduced from mid via Tups' fundep
-- leaf can be deduced from tree
而且它有效

> ltmap (+(2 :: Integer)) [[[(5, 2)]], [], [[(2, 8), (4, 5)]]]
[[[(7,4)]],[],[[(4,10),(6,7)]]]

我认为使用嵌套列表的更直接表示法会让您获得更多好处:
数据嵌套a=Flat a |嵌套(嵌套[a])
几个问题。
t
是否确定
LTTree
中的
leaf
t
是否在
Tups
中确定
a
?我认为您的类需要fundeps或类型族来表达这些依赖关系。我甚至不确定您是否真的需要这些类:您想解决什么问题?这种用TypeClass表示数据的策略实际上并没有给您带来任何好处,而正确编码显然是非常重要的。正如其他评论者所指出的,为什么不表示您的数据。。。作为数据?您可以使用例如
data ConstrainedRec c来表示存在的量化记录,其中CRec::Forall r c=>Rec r->ConstrainedRec c
(其中
Rec
Forall
由CTrex提供)。您没问题,
data
方法可能更简单,也同样有效。我是Haskell的新手,所以我并不总是确定什么是适合这份工作的工具。不过,学习如何作为类型类进行编码是很有趣的。非常感谢这篇非常好的演练!一个问题:为什么需要
(leaf~tree)=>ListTree leaf tree
而不是
ListTree a
?是不是
2
1
的有效实例?还是其他原因?