【发布时间】:2026-02-10 05:55:02
【问题描述】:
我正在阅读 Introdution to Haskell 课程,他们正在介绍众所周知的河内塔问题作为第一堂课的作业。我动心了,写了一个解决方案:
type Peg = String
type Move = (Peg, Peg)
hanoi :: Int -> Peg -> Peg -> Peg -> [Move]
hanoi n b a e
| n == 1 = [(b, e)]
| n > 1 = hanoi (n - 1) b e a ++ hanoi 1 b a e ++ hanoi (n - 1) a b e
| otherwise = []
我玩了一点,发现它显然使用了尾调用优化,因为它在恒定内存中工作。
Clojure 是我大部分时间都在使用的语言,因此我面临着编写 Clojure 解决方案的挑战。幼稚的被丢弃,因为我想写它来使用 TCO:
(defn hanoi-non-optimized
[n b a e]
(cond
(= n 1) [[b e]]
(> n 1) (concat (hanoi-non-optimized (dec n) b e a)
(hanoi-non-optimized 1 b a e)
(hanoi-non-optimized (dec n) a b e))
:else []))
嗯,Clojure 是 JVM 托管的,因此默认情况下没有 TCO,应该使用 recur 来获取它(我知道这个故事......)。另一方面,recur 施加了一些语法约束,因为它必须是最后一个表达式 - 必须是尾部。我感觉有点糟糕,因为我仍然无法编写一个像 Haskell 中那样简短/富有表现力的解决方案并同时使用 TCO。
是否有一个我目前看不到的简单解决方案?
我非常尊重这两种语言,并且已经知道这是我的方法而不是 Clojure 本身的问题。
【问题讨论】:
标签: haskell recursion clojure tail-recursion towers-of-hanoi