Вставка значений в Trie - PullRequest
1 голос
/ 21 мая 2019

Я нашел эту реализацию Trie в каталоге SML:

    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?

1 Ответ

1 голос
/ 21 мая 2019

Прежде всего, если у вас нет интеллектуальных прав на этот код, вам следует ссылаться на то, где вы его нашли, а не повторять его, поскольку вы не предоставляете никаких атрибутов.Во-вторых, код, кажется, работает нормально.Здесь я вставляю пару ключей и ищу их:

$ 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
...