Last active
November 7, 2016 16:02
-
-
Save psaxton/c6ec6841a63bf0092304787697dc3beb to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
type Trie<'T when 'T : comparison> = { | |
IsTerminal: bool; | |
Children: Map<'T, Trie<'T>>; | |
} | |
module Trie = | |
module Map = | |
let addOrReplace key value map = | |
map | |
|> Map.remove key | |
|> Map.add key value | |
let empty = { | |
IsTerminal = false; | |
Children = Map.empty; | |
} | |
let isEmpty trie = | |
Map.isEmpty trie.Children && not trie.IsTerminal | |
let rec add branch trie = | |
match branch with | |
| [] -> | |
{ trie with IsTerminal = true; } | |
| el::els -> | |
let child = | |
trie.Children | |
|> Map.tryFind el | |
|> defaultArg <| empty | |
|> add els | |
let children = | |
trie.Children | |
|> Map.addOrReplace el child | |
{ trie with Children = children } | |
let rec contains branch trie = | |
match branch with | |
| [] -> trie.IsTerminal | |
| el::els -> | |
Map.tryFind el trie.Children | |
|> Option.exists (contains els) | |
let rec toSeq trie = | |
seq { | |
for KeyValue(label, trie) in trie.Children do | |
if trie.IsTerminal then yield [label] | |
let children = toSeq trie | |
for child in children do | |
yield label :: child | |
} | |
module Test = | |
let ``empty isEmpty`` = | |
isEmpty empty | |
do assert ``empty isEmpty`` | |
let ``add can add char into root`` = | |
let result = empty |> add ['a'] | |
Map.containsKey 'a' result.Children | |
do assert ``add can add char into root`` | |
let ``add can add char into multiple levels`` = | |
let result = empty |> add ['a'..'d'] | |
Map.containsKey 'd' (((result.Children |> Map.find 'a').Children |> Map.find 'b').Children |> Map.find 'c').Children | |
do assert ``add can add char into multiple levels`` | |
let ``contains finds branches that exist in tree`` = | |
let result = empty |> add ['a'..'d'] | |
contains ['a'..'d'] result | |
do assert ``contains finds branches that exist in tree`` | |
let ``contains does not find incomplete branches`` = | |
let result = empty |> add ['a'..'d'] | |
not (result |> contains ['a'..'c']) | |
do assert ``contains does not find incomplete branches`` | |
let ``contains does not find extended branches`` = | |
let result = empty |> add ['a'..'d'] | |
not (result |> contains ['a'..'e']) | |
do assert ``contains does not find extended branches`` |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment