I really like the repmin
problem:
Write down
repmin :: Tree Int -> Tree Int
, which replaces all the numbers in the tree by their minimum in a single pass.
If I were writing something like this in python, I would go for passing values by their reference (let's say one-element lists instead of numbers is good enough):
def repmin(tree, wrapped_min_link=None):
x, subforest = tree
if wrapped_min_link is None:
wrapped_min_link = [x]
else:
[m] = wrapped_min_link
wrapped_min_link = [min(m, x)]
n = len(subforest)
subforest_min = [None] * n
for i in range(n):
if subforest[i]:
subforest_min[i] = repmin(subforest[i], wrapped_min_link)
return (wrapped_min_link, subforest_min)
It seems to me like a fitting way to wrap one's head around the knot-tying solution in Haskell (I wrote this one for rose trees from Data.Tree
):
copyRose :: Tree Int -> Int -> (Tree Int, Int)
copyRose (Node x []) m = (Node m [], x)
copyRose (Node x fo) m =
let
unzipIdMinimum =
foldr (\ ~(a, b) ~(as, bmin) -> (a:as, b `min` bmin)) ([], maxBound :: Int)
(fo', y) = unzipIdMinimum . map (flip copyRose m) $ fo
in (Node m fo', x `min` y)
repmin :: Tree Int -> Tree Int
repmin = (loop . uncurry) copyRose
Yet, I reckon the solutions to work very differently. Here is my understanding of the latter one:
Let us rewrite loop
for (->)
a bit:
loop f b = let cd = f (b, snd cd) in fst cd
I reckon it to be loop
for (->)
's workalike as snd
gives the same degree of laziness as pattern-matching within let
.
So, when repmin
traverses through the tree, it is:
- Building up the minimum in the tree to be returned as the second element of the pair.
- Leaves
snd $ copyRose (tree, m)
behind in every node.
Thus, when the traversal comes to an end, the programme knows the value of snd $ copyRose (tree, m)
(that is, the minimum in the tree) and is able to show it whenever some node of the tree is being computed.
Do I understand repmin
in Haskell correctly?