开发者

newbie F# trie implementation gone wrong

开发者 https://www.devze.com 2023-02-11 19:42 出处:网络
I am trying to implement a trie data structure in F#. I am having some problems. I cannot debug the word insertion function. None of my breakpoint inside this function is reached something crashes but

I am trying to implement a trie data structure in F#. I am having some problems. I cannot debug the word insertion function. None of my breakpoint inside this function is reached something crashes but I don't see any error. Also I am having serious doubts if I implemented the thing right. Anyway here is the code:

type TrieNode =
    | SubNodes of char * bool * TrieNode list
    | Nil
    member this.Char = match this with | Nil -> ' '
                                       | SubNodes(c,weh,subnodes) -> c
    member this.GetChild(c:char) = match this with  | Nil -> []
                                                    | SubNodes(c,weh,subnodes) ->[ (List.filter(fun (this:TrieNode) -> this.Char = c) subnodes).Head ]

    member this.AWordEndsHere = match this with | Nil -> false
                                                | SubNodes(c,weh,subnodes) -> weh
module TrieFunctions = 
    let rec insertWord (wordChars:char list) = function
        | Nil -> SubNodes(wordChars.Head, false, [])
        | SubNodes(c, weh, subnodes) as node ->
            let child = node.GetChild(wordChars.Head)
            if child = [] then 
                SubNodes(wordChars开发者_如何学C.Head,false,[insertWord wordChars.Tail node])
            else
                SubNodes(wordChars.Head,false,[insertWord wordChars.Tail child.Head])


type Trie(inner : TrieNode) =

    member this.InsertWord(wordChars:char list) = TrieFunctions.insertWord(wordChars)


  let trie = Trie(SubNodes(' ',false,List.empty)).InsertWord(['g';'i';'g';'i'])

So my questions are:

1. how can I get debug access to the insertWord function? Why am I not getting it now? Why am I not seeing an error?

2. How can I make the function insert word return a list of TrieNode objects so that I won't have to wrap the call around square brackets ("[","]"). I think this is an error.

3. Any other advice you can give me on implementing this data structure in F# is welcomed I know I must be doing a lot of things wrong as I am very new to this language. I know for example that the word insertion function is flawed because it doesn't check if the list is empty or not so it ends prematurely. I wanted to cross that bridge when I got to it.

Thank you in advance

Thank you in advance


  1. You are probably failing to trigger your breakpoint because you aren't fully applying insertWords: it takes two curried parameters, but you're only passing the single argument wordChars in. Perhaps you meant to define your Trie type like this instead?

    type Trie(inner : TrieNode) =
      member this.InsertWord(wordChars:char list) = TrieFunctions.insertWord wordChars inner
    
  2. Well, you could wrap all of your return values in [] to make them singleton lists and then not wrap the recursive calls to insertWords. However, it seems likely that there's something wrong with your algorithm (either way), since you only ever get singleton lists...

    Note that at the moment you're completely discarding the existing subnodes list - if you want to append to the front of it, use (insertWord wordChards.Tail node)::subnodes instead. However, sometimes you'll want to replace an existing entry rather than append a new one, which will require more effort.

  3. There are several issues. Here are a few to get you started:

    • Try to avoid using Head, particularly since you don't always know that your lists are non-empty when you're calling it.
    • When you're inserting a word into an empty Trie, you're dropping all but the first character! Similarly, you need to reconsider your recursive calls too.
    • More importantly, your TrieNode type has a bit of a problem. Can you write out the resulting trie you would expect to see which just contains the two words "in" and "to"?


Regarding your first question, as @kvb said, you're partially applying insertWord. While defining it you are specifying an explicit argument wordChars and by using the function construct for pattern matching you're basically adding a second parameter of type TrieNode so your function ends up with the following signature:

insertWord : char list -> TrieNode -> TrieNode

Since in your call to InsertWord (which is just a wrapper to insertWord) you only provide one argument (a char list) the function won't get called, but you'll get a function expecting a TrieNode back. InsertWord's signature makes that clear:

InsertWord : wordChars:char list -> (TrieNode -> TrieNode)

Note the parenthesis.

You'll probably want to provide a Nil in your case since conceptually you're extending an empty trie:

let trie = Trie(SubNodes(' ',false,List.empty)).InsertWord(['g';'i';'g';'i']) Nil

You'll find an example implementation of a trie structure here: http://lepensemoi.free.fr/index.php/2009/10/15/trie-and-anagrams-with-f

0

精彩评论

暂无评论...
验证码 换一张
取 消