Sml 在Trie中插入值
我在SML目录中找到了Trie的这个实现:Sml 在Trie中插入值,sml,Sml,我在SML目录中找到了Trie的这个实现: signature DICT = sig type key = string (* concrete type *) type 'a entry = key * 'a (* concrete type *) type 'a dict (* abstract type *) val empty :
signature DICT =
sig
type key = string (* concrete type *)
type 'a entry = key * 'a (* concrete type *)
type 'a dict (* abstract type *)
val empty : 'a dict
val lookup : 'a dict -> key -> 'a option
val insert : 'a dict * 'a entry -> 'a dict
val toString : ('a -> string) -> 'a dict -> string
end; (* signature DICT *)
exception InvariantViolationException
structure Trie :> DICT =
struct
type key = string
type 'a entry = key * 'a
datatype 'a trie =
Root of 'a option * 'a trie list
| Node of 'a option * char * 'a trie list
type 'a dict = 'a trie
val empty = Root(NONE, nil)
(* val lookup: 'a dict -> key -> 'a option *)
fun lookup trie key =
let
(* val lookupList: 'a trie list * char list -> 'a option *)
fun lookupList (nil, _) = NONE
| lookupList (_, nil) = raise InvariantViolationException
| lookupList ((trie as Node(_, letter', _))::lst, key as letter::rest) =
if letter = letter' then lookup' (trie, rest)
else lookupList (lst, key)
| lookupList (_, _) =
raise InvariantViolationException
(*
val lookup': 'a trie -> char list
*)
and lookup' (Root(elem, _), nil) = elem
| lookup' (Root(_, lst), key) = lookupList (lst, key)
| lookup' (Node(elem, _, _), nil) = elem
| lookup' (Node(elem, letter, lst), key) = lookupList (lst, key)
in
lookup' (trie, explode key)
end
(*
val insert: 'a dict * 'a entry -> 'a dict
*)
fun insert (trie, (key, value)) =
let
(*
val insertChild: 'a trie list * key * value -> 'a trie list
Searches a list of tries to insert the value. If a matching letter
prefix is found, it peels of a letter from the key and calls insert'.
If no matching letter prefix is found, a new trie is added to the list.
Invariants:
* key is never nil.
* The trie list does not contain a Root.
Effects: none
*)
fun insertChild (nil, letter::nil, value) =
[ Node(SOME(value), letter, nil) ]
| insertChild (nil, letter::rest, value) =
[ Node(NONE, letter, insertChild (nil, rest, value)) ]
| insertChild ((trie as Node(_, letter', _))::lst, key as letter::rest, value) =
if letter = letter' then
insert' (trie, rest, value) :: lst
else
trie :: insertChild (lst, key, value)
| insertChild (Root(_,_)::lst, letter::rest, value) =
raise InvariantViolationException
| insertChild (_, nil, _) = (* invariant: key is never nil *)
raise InvariantViolationException
(*
val insert': 'a trie * char list * 'a -> 'a trie
Invariants:
* The value is on the current branch, including potentially the current node we're on.
* If the key is nil, assumes the current node is the destination.
Effects: none
*)
and insert' (Root(_, lst), nil, value) = Root(SOME(value), lst)
| insert' (Root(elem, lst), key, value) = Root(elem, insertChild (lst, key, value))
| insert' (Node(_, letter, lst), nil, value) = Node(SOME(value), letter, lst)
| insert' (Node(elem, letter, lst), key, value) = Node(elem, letter, insertChild (lst, key, value))
in
insert'(trie, explode key, value)
end
(*
val toString: ('a -> string) -> 'a dict -> string
*)
fun toString f trie =
let
val prefix = "digraph trie {\nnode [shape = circle];\n"
val suffix = "}\n"
(* val childNodeLetters: 'a trie list * char list -> char list *)
fun childNodeLetters (lst, id) =
(foldr
(fn (Node(_, letter, _), acc) => letter::acc
| _ => raise InvariantViolationException) nil lst)
(* val edgeStmt: string * string * char -> string *)
fun edgeStmt (start, dest, lbl) =
start ^ " -> " ^ dest ^ " [ label = " ^ Char.toString(lbl) ^ " ];\n"
(* val allEdgesFrom: char list * char list *)
fun allEdgesFrom (start, lst) =
(foldr
(fn (letter, acc) =>
acc ^ edgeStmt(implode(start), implode(start @ [letter]), letter))
"" lst)
(* val labelNode: stirng * string -> string *)
fun labelNode (id: string, lbl: string) =
id ^ " [ label = \"" ^ lbl ^ "\" ];\n"
fun toString' (Root(elem, lst), id) =
let
val idStr = implode(id)
val childLetters = childNodeLetters(lst, id)
val childStr = foldr (fn (trie, acc) => acc ^ toString'(trie, id)) "" lst
in
(case elem
of SOME(value) =>
labelNode (idStr, f(value)) ^
allEdgesFrom (id, childLetters)
| NONE =>
labelNode (idStr, "") ^
allEdgesFrom (id, childLetters)) ^ childStr
end
| toString' (Node(elem, letter, lst), id) =
let
val thisId = id @ [letter]
val idStr = implode(thisId)
val childLetters = childNodeLetters(lst, thisId)
val childStr = foldr (fn (trie, acc) => acc ^ toString'(trie, thisId)) "" lst
in
(case elem
of SOME(value) =>
labelNode (idStr, f(value)) ^
allEdgesFrom (thisId, childLetters)
| NONE =>
labelNode (idStr, "") ^
allEdgesFrom (thisId, childLetters)) ^ childStr
end
in
prefix ^ (toString' (trie, [#"_", #"R"])) ^ suffix
end
end
每当我尝试使用上述函数插入或查找此实现中的字符串时:insert,lookup我都会遇到以下错误:
stdIn:1.2-1.8 Error: unbound variable or constructor: lookup
stdIn:1.2-1.8 Error: unbound variable or constructor: insert
我认为这是一个声明问题,但我不知道如何解决它。
为什么会发生这种情况?我如何在Trie数据结构中正确插入或搜索?首先,如果您没有此代码的知识产权,您应该链接到找到它的位置,而不是重复它,因为您没有提供属性。其次,代码似乎运行良好。在这里,我插入两个键并查找它们:
$sml trie.sml
新泽西州v110.79标准毫升[建成日期:2017年8月8日星期二23:21:20]
[打开trie.sml]
签名口述=
信号
类型键=字符串
键入“a条目=键*”a
键入一个dict
val empty:“一条格言
val查找:“一个dict->key->”一个选项
val insert:'a dict*'a entry->'a dict
val-toString:('a->string)->'a dict->string
结束
[自动加载]
[库$SMLNJ-BASIS/BASIS.cm稳定]
[库$SMLNJ-BASIS/(BASIS.cm):BASIS-common.cm稳定]
[自动加载完成]
异常不变量ViolationException异常
结构Trie:DICT
-val foo=Trie.insert(Trie.empty,(“foo”,42));
val foo=-:int Trie.dict
-val bar=Trie.insert(foo,(“fab”,43));
val bar=-:int Trie.dict
-Trie.lookup条“foo”;
val it=大约42:int选项
-Trie.lookup条“fab”;
val it=大约43:int选项
-Trie.查找栏“wat”;
val it=NONE:int选项
我已投票结束此问题,因为您指出您找到了此代码,但没有将其归为属性,而且问题的根源是尚未发布的代码。您遗漏了如何使用它的详细信息。(我想你可能想读一下你最喜欢的SML书中关于结构的章节。)