12

私は Stuart Halloway の本 Programming Clojure に取り組もうとしています。この機能的なもの全体は、私にとって非常に新しいものです。

方法がわかりました

(defn fibo[]
    (map first (iterate (fn [[a b]] [b (+ a b)]) [0 1])))

フィボナッチ数列を遅延生成します。私はなぜなのか理解していない

(last (take 1000000 (fibo)))

働きながら

(nth (fibo) 1000000)

OutOfMemoryError をスローします。この2つの表現の違いを誰か説明してくれませんか? (nth) はどういうわけかシーケンスの先頭を保持していますか?

ありがとう!

4

3 に答える 3

4

あなたはグーグルグループで議論された問題について話していると思います、そしてリッチヒッキーは問題を解決するパッチを提供しました。そして、この本は後で出版されましたが、このトピックについては取り上げていませんでした。

clojure1.3では、あなたのnth例は機能のマイナーな改善で動作しfiboます。現在、1.3での変更により、M任意精度を使用するように明示的にフラグを立てる必要があります。そうしないと、。に該当しthrowIntOverflowます。

(defn fibo[]
  (map first (iterate (fn [[a b]] [b (+ a b)]) [0M 1M])))

そしてこれらの変更で

(nth (fibo) 1000000)

成功する(十分なメモリがある場合)

于 2011-12-15T17:02:39.740 に答える
1

Clojure のどのバージョンを使用していますか? repl で (clojure-version) を試してください。1.3.0 では、両方の式で同じ結果が得られます。つまり、整数オーバーフローです。

為に

(defn fibo[]
    (map first (iterate (fn [[a b]] [b (+ a b)]) [(bigint 0) 1])))

両方の式で正しい結果が得られます (非常に大きな整数...)。

于 2011-12-15T17:00:05.427 に答える
0

マシンの特定のメモリ制限に達している可能性があり、機能の実際の違いではないと思います。

https://github.com/clojure/clojure/blob/master/src/jvm/clojure/lang/RT.javaの nth のソース コードを 見ると、nth または take がヘッドを保持しているようには見えません。

ただし、nth は項目番号によるカウントではなく、0 から始まるインデックスを使用します。nth のコードは、シーケンスの 1000001 番目の要素 (インデックス 1000000 の要素) を選択します。take を使用してコーディングすると、1000000 要素シーケンスの最後の要素が返されます。それがインデックス 999999 の項目です。fib の成長速度を考えると、最後の項目がラクダの背中を折った可能性があります。

また、1.3.0 のソースをチェックしていました。おそらく、以前のバージョンには異なる実装がありました。fibo を 1.3.0 で適切に動作させるには、数値を bignum に昇格させる算術関数を使用する必要があります。

(defn fibo[]
    (map first (iterate (fn [[a b]] [b (+' a b)]) [0 1])))
于 2011-12-15T18:39:40.270 に答える