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
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 argumentwordChars
in. Perhaps you meant to define yourTrie
type like this instead?type Trie(inner : TrieNode) = member this.InsertWord(wordChars:char list) = TrieFunctions.insertWord wordChars inner
Well, you could wrap all of your return values in
[]
to make them singleton lists and then not wrap the recursive calls toinsertWords
. 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.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"
?
- Try to avoid using
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
精彩评论