私はIntrodution to Haskellコースを読んでおり、彼らはよく知られたハノイ塔問題をファーストクラスの宿題として紹介しています。私は誘惑とソリューション書いた:TCOに最適化されたClojureのハノイ塔
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を持っていない、もう1つはそれを得るためにrecur
を使用する必要があります。 ..)。一方、recur
は最後の式でなければならないので構文上の制約を課します。つまり、テールでなければなりません。なぜなら、Haskellのように短く/表現力豊かなソリューションを書くことができず、同時にTCOを使うことができないからです。
私は現時点で見ることができない簡単な解決法はありますか?
私は両方の言語に大きな敬意を払っていますが、これはClojure自身よりも私のアプローチではむしろ問題であることをすでに知っています。
ありがとうございます。しかし、私が 'ghc-8.0.1'でHaskellの機能をコンパイルし、9999のようにもっと多くのディスクで実行すると、決してメモリを超えません。実際、プロセッサの負荷は変わってもメモリは一定であり、スタックオーバーフローは発生しません。私が理解しているように、大きなnのスタックオーバーフローが発生するはずです。 – foki
私の理解は、 'n '個のディスクの場合、再帰の深さも' n'になります。私は10000がそれほど多くないと思います。スタンドアロンの実行ファイルを 'stats 'の' + RTS -s'スイッチで実行していますか?完全なプロファイリングオプションもありますので、それについてもっと詳しく知ることができなければなりません。 –
Clojure TRMCOのバージョンを確認できますか? – Thumbnail