您可以从为字典定义签名开始:
signature DICT =
sig
type (''k, 'v) dict
val empty : (''k, 'v) dict
val insert : ''k -> 'v -> (''k, 'v) dict -> (''k, 'v) dict
val lookup : ''k -> (''k, 'v) dict -> 'v option
end
''k(一种相等类型)假设我唯一需要知道的关于键值存储的键是可以比较它是否相等,这样我就可以在查找时找到正确的键。这让我可以使用 O(n) 插入和查找来构建一个简单的基于列表的字典:
structure ListDict : DICT =
struct
type (''k, 'v) dict = (''k * 'v) list
val empty = []
fun insert k v [] = [(k, v)]
| insert k v ((k2,v2) :: rest) =
if k = k2 then (k,v) :: rest else (k2,v2) :: insert k v rest
fun lookup k [] = NONE
| lookup k ((k2, v) :: rest) =
if k = k2 then SOME v else lookup k rest
end
''k 的类型级别限制意味着,例如,我不能将我的字典表示为二叉搜索树,因为排序事物(小于、等于、大于)不是相等的属性类型,或将我的字典表示为哈希表,因为查找值的哈希也不是相等类型的属性。
所以我可能更喜欢键可以被排序或散列。不幸的是,SML 没有内置的可排序或可散列的类型类,就像它具有相等类型一样。克服此限制的一种方法是更改接口,以便将比较或散列函数传递给模块。以下是可能的比较方式:
signature ORD =
sig
type t
val compare : t -> t -> order
end
signature DICT =
sig
type k
type 'v dict
val empty : 'v dict
val insert : k -> 'v -> 'v dict -> 'v dict
val lookup : k -> 'v dict -> 'v option
end
这让我可以编写一个基于二叉树的字典结构:
functor TreeDict (Ord : ORD) : DICT =
struct
type k = Ord.t
datatype 'v dict = Leaf | Node of k * 'v * 'v dict * 'v dict
val empty = Leaf
fun insert k v Leaf = Node (k, v, Leaf, Leaf)
| insert k v (Node (k2, v2, left, right)) =
case Ord.compare (k, k2) of
EQ => Node (k, v, left, right)
| LT => Node (k2, v2, insert k v left, right)
| GT => Node (k2, v2, left, insert k v right)
fun lookup k Leaf = NONE
| lookup k (Node (k2, v, left, right)) =
case Ord.compare (k, k2) of
EQ => SOME v
| GT => lookup k right
| LT => lookup k left
end
缺点是我必须具体说明ORD 我想要什么。
例如键为int 的基于树的字典可以这样制作:
structure IntTreeDict = TreeDict(
struct
type t = int
val compare = Int.compare
end)