【问题标题】:Inserting values in a Trie在 Trie 中插入值
【发布时间】:2019-05-21 14:54:03
【问题描述】:

我在 SML 目录中找到了 Trie 的这种实现:

    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

每当我尝试使用上述函数在此实现中插入或查找字符串时:插入,查找我都会收到以下错误:

stdIn:1.2-1.8 Error: unbound variable or constructor: lookup
stdIn:1.2-1.8 Error: unbound variable or constructor: insert

我认为这是一个声明问题,但我不知道如何解决它。 为什么会发生这种情况?如何在 Trie 数据结构中正确插入或搜索?

【问题讨论】:

  • 我已投票结束此问题,因为您表示您找到了此代码,但没有归咎于它,而且您的问题的根源是尚未发布的代码。跨度>
  • 您遗漏了如何尝试使用它的详细信息。 (我怀疑您可能想阅读您最喜欢的 SML 书籍中关于结构的章节。)

标签: sml


【解决方案1】:

首先,如果您没有此代码的知识产权,您应该链接到您找到它的地方而不是重复它,因为您没有提供任何归属。其次,代码似乎工作正常。在这里,我插入了几个键并查找它们:

$ sml trie.sml 
Standard ML of New Jersey v110.79 [built: Tue Aug  8 23:21:20 2017]
[opening trie.sml]
signature DICT =
  sig
    type key = string
    type 'a entry = key * 'a
    type 'a dict
    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
[autoloading]
[library $SMLNJ-BASIS/basis.cm is stable]
[library $SMLNJ-BASIS/(basis.cm):basis-common.cm is stable]
[autoloading done]
exception InvariantViolationException
structure 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 bar "foo";
val it = SOME 42 : int option
- Trie.lookup bar "fab";
val it = SOME 43 : int option
- Trie.lookup bar "wat";
val it = NONE : int option

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-02-01
    • 2017-12-02
    • 2023-02-02
    • 2023-03-09
    • 2014-03-29
    • 2021-11-11
    相关资源
    最近更新 更多