Consider the Fork
. It has two subtrees, and each of those subtrees has some encoding.
Let's say that the left subtree encoding is:
[(x, pathToX), (y, pathToY)]
And let's say that the right subtree encoding is:
[(a, pathToA), (b, pathToB)]
Now, can you see what the encoding of the whole fork should be? It should be this:
[(a, True : pathToA), (b, True : pathToB), (x, False : pathToX), (y, False : pathToY)]
Do you agree with that? If not, give it a think. Maybe work through some small examples. Until you agree that this is the case.
See what I did there? I prepended a False
to each path in the left subtree, and then I prepended True
to each path of the right subtree.
Let's write that down in Haskell syntax:
encode (Fork left right) = prependToEach False (encode left) ++ prependToEach True (encode right)
Now you may have noticed that I cheated here: I'm using a function prependToEach
that doesn't exist. Well, no matter, let's define it!
prependToEach x list = map (prepend x) list
See? Prepending a thing to each element of the list is just mapping a single-element prepending function over the list.
But of course, I cheated again: there is no such function as prepend
yet. So let there be one!
prepend x (a, path) = (a, x : path)
And there you go! Now all that's left is to define the base case: what should the path of a Leaf
be? Well, according to the example you gave, each Leaf
would have an empty path, reflecting the fact that you don't need to take any turns to get from that leaf to that same leaf:
encode (Leaf a) = [(a, [])]
And now, putting it all together:
encode :: HTree a -> [(a, [Bool])]
encode (Leaf a) = [(a, [])]
encode (Fork left right) = prependToEach False (encode left) ++ prependToEach True (encode right)
where
prependToEach x list = map (prepend x) list
prepend x (a, path) = (a, x : path)
And now that we understand how it was constructed and why, we may shorten it a little by making use of list comprehensions (though I consider this step very much optional):
encode :: HTree a -> [(a, [Bool])]
encode (Leaf a) = [(a, [])]
encode (Fork left right) = [(x, False : p) | (x, p) <- encode left] ++ [(x, True : p) | (x, p) <- encode right]
P.S. note that a type cannot be named htree
, because type names in Haskell must be capitalized. You may notice that I renamed it to HTree
in my final snippet.
there aren't a lot of online resources
Is there a particular type of resource you find most helpful? A lot of people recommend "Learn you a Haskell". It's free online. Here is the chapter on recursion: learnyouahaskell.com/recursion – Garrison