Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/haskell/9.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 没有“Ord”的集合式数据结构?_Haskell_Set - Fatal编程技术网

Haskell 没有“Ord”的集合式数据结构?

Haskell 没有“Ord”的集合式数据结构?,haskell,set,Haskell,Set,鉴于以下类型: import Data.Set as Set -- http://json.org/ type Key = String data Json = JObject Key (Set JValue) | JArray JArr deriving Show data JObj = JObj Key JValue deriving Show data JArr = Arr [JValue] deriving

鉴于以下类型:

import Data.Set as Set

-- http://json.org/

type Key = String

data Json = JObject Key (Set JValue)
            | JArray JArr
            deriving Show

data JObj = JObj Key JValue
            deriving Show

data JArr = Arr [JValue] deriving Show

data Null = Null deriving Show

data JValue = Num Double
              | S String
              | B Bool
              | J JObj
              | Array JArr
              | N Null
               deriving Show
我使用单个元素创建了一个
JObject键(设置值)

ghci> JObject "foo" (Set.singleton (B True))
JObject "foo" (fromList [B True])
但是,当我试图创建一个2元素集时,我得到了一个编译时错误:

ghci> JObject "foo" (Set.insert (Num 5.5) $ Set.singleton (B True))

<interactive>:159:16:
    No instance for (Ord JValue) arising from a use of ‘insert’
    In the expression: insert (Num 5.5)
    In the second argument of ‘JObject’, namely
      ‘(insert (Num 5.5) $ singleton (B True))’
    In the expression:
      JObject "foo" (insert (Num 5.5) $ singleton (B True))
ghci>JObject“foo”(Set.insert(Num 5.5)$Set.singleton(B True))
:159:16:
没有因使用“插入”而产生的(Ord JValue)实例
在表达式中:插入(Num 5.5)
在“JObject”的第二个参数中,即
“(插入(数字5.5)$singleton(B真))”
在表达式中:
JObject“foo”(插入(数字5.5)$singleton(B真))
所以我问,“为什么
JValue
需要实现
Ord
typeclass?”

医生们回答了这个问题

Set的实现基于大小平衡的二叉树(或有界平衡的树)


但是,是否有一个集合,例如,非有序的数据结构,它不需要我可以使用
Ord
的实现?

您几乎总是需要至少
Eq
来实现一个集合(或者至少能够编写
Eq
实例,无论是否存在)。只有
Eq
会让你的效率非常低。您可以使用
Ord
Hashable
来改进这一点

这里您可能想做的一件事是使用trie,这将使您能够利用嵌套结构,而不是不断地与之对抗

你可以先看看。这似乎没有为您的
数组提供任何东西,因此您可能需要添加一些东西

为什么
Eq
不够好 实现集合的最简单方法是使用列表:

type Set a = [a]

member a [] = False
member (x:xs) | a == x = True
              | otherwise = member a xs

insert a xs | member a xs = xs
            | otherwise = a:xs
这是不好的(除非元素很少),因为您可能必须遍历整个列表才能查看某个元素是否是成员

为了改善情况,我们需要使用某种树:

data Set a = Node a (Set a) (Set a) | Tip
我们可以制作很多不同种类的树,但是为了使用它们,我们必须能够在每个节点上决定要使用哪一个分支。如果我们只有
Eq
,就没有办法选择正确的。如果我们有
Ord
(或
Hashable
),这就给了我们一种选择的方式

trie方法基于数据结构构造树。当您的类型是深度嵌套的(列表记录数组的列表…)时,哈希或比较可能非常昂贵,因此trie可能会更好

作战需求文件的旁注 虽然我认为您不应该在这里使用
Ord
方法,但它通常是正确的方法。在某些情况下,您的特定类型可能没有自然排序,但有一些有效的方法可以对其元素进行排序。在这种情况下,您可以使用
newtype

newtype WrappedThing = Wrap Thing

instance Ord WrappedThing where
  ....

newtype ThingSet = ThingSet (Set WrappedThing)
insertThing thing (ThingSet s) = ThingSet (insert (Wrap thing) s)
memberThing thing (ThingSet s) = member (WrapThing) s
...

在某些情况下,另一种方法是定义一个“基本类型”,它是一个
Ord
实例,但仅在其周围导出一个
newtype
包装器;您可以对所有内部函数使用基类型,但导出的类型是完全抽象的(而不是
Ord
实例)。

您可以使用
派生(Show,Ord,Eq)
来派生所需的实例,因此
Ord
要求不是什么大问题。@chi,我认为trie更合适。实现集合的另一种常见方法是使用哈希映射。当然,这需要指定散列函数。对于一般实现,请参见如何定义可散列类以及如何实现(纯)散列映射。您可以说,请解释,
只有Eq将导致效率极低。
?基本上,如果您想(比如)检查某个元素是否在此集合中,您唯一的选择是检查集合中的所有元素。使用
Ord
您可以使用二进制搜索,这要快得多。像废弃样板文件这样的东西难道不允许基于任何数据类型的通用结构实现吗?还是Arr太不透明,需要为泛型分解遍历添加显式支持?@jdlugosz,我不知道。我对GHC泛型几乎一无所知。据我所知,
generic-trie
包不支持这一点,但我认为可以添加专门的
Array
支持,而无需任何理论上的困难。