【发布时间】:2020-11-03 21:38:31
【问题描述】:
repmin 问题是众所周知的。我们得到了树的数据类型:
data Tree a = Leaf a | Fork (Tree a) a (Tree a) deriving Show
我们需要编写一个函数 (repmin),该函数将获取一棵数字树并将其中的所有数字替换为一次性的最小值。也可以沿途打印树(假设函数repminPrint 执行此操作)。 repmin 和前、后和有序 repminPrint 都可以使用值递归轻松写下。这是一个有序repminPrint的示例:
import Control.Arrow
replaceWithM :: (Tree Int, Int) -> IO (Tree Int, Int)
replaceWithM (Leaf a, m) = print a >> return (Leaf m, a)
replaceWithM (Fork l mb r, m) = do
(l', ml) <- replaceWithM (l, m)
print mb
(r', mr) <- replaceWithM (r, m)
return (Fork l' m r', ml `min` mr `min` mb)
repminPrint = loop (Kleisli replaceWithM)
但是如果我们想把级别顺序repminPrint 写下来呢?
我的猜测是我们不能使用队列,因为我们需要ml 和mr 来更新m 的绑定。我看不出这怎么会因队列而下降。我写了一个 level-order Foldable Tree 的实例来说明我的意思:
instance Foldable Tree where
foldr f ini t = helper f ini [t] where
helper f ini [] = ini
helper f ini ((Leaf v) : q = v `f` helper f ini q
helper f ini ((Fork l v r) : q) = v `f` (helper f ini (q ++ [l, r]))
如您所见,在当前递归调用期间,我们不会在 l 和 r 上运行任何内容。
那么,如何做到这一点呢?我希望得到提示而不是完整的解决方案。
【问题讨论】:
-
我认为遍历顺序无关紧要……我可能错了,但我会懒惰:构建一个与输入形状相同的树,其中每个值都替换为对same “最小” thunk,其值是从整个树计算的。你可以用
ArrowLoop来做,但我会用MonadFix和do…rec…符号。当然,虽然在源代码中只有一个 explicit 遍历,但在运行时有两个,在某种程度上,是交错的:一个用于树的 结构(分配一个新树,其节点都指向同一个 thunk),一个指向它的 values(强制 thunk)。 -
我不确定这是否真的可行:考虑如何以 BFS 顺序遍历树,并在此遍历期间同时“重建”它。这是一个比您要解决的问题更简单的问题,但绝对必要的是您首先可以做到这一点。您将如何解决这个更简单的问题?
-
might be related。 (也,@alias)
-
@WillNess 这真是太棒了。它是否只构建“完整”树?即,完全平衡?我怀疑 OP 的案例是针对一般树的。
-
@alias 我想是的,是的。在边缘也偏左。否则它将不得不返回一个树列表,对不确定性进行建模。
标签: haskell tree monads breadth-first-search tying-the-knot