4

フィボナッチ数の遅延拡張無限シーケンスを返す関数を作成したいと思います。

今のところ、次のようにシーケンスをトップレベルの名前空間で使用できるようにすることができます。

(def fibonacci-numbers
  (lazy-cat [0 1] (map + fibonacci-numbers (rest fibonacci-numbers))))

ただし、これは、それらを大量に消費し始めると、ガベージコレクションを制御できなくなることを意味します。

私は次のようなことをしたいと思っています:

(defn fibonacci-numbers-fn []
  (lazy-cat [0 1] (map + (fibonacci-numbers-fn) (rest (fibonacci-numbers-fn)))))

O(2 ^ n)シーケンスを作成することになるため、これは明らかに機能しません。関数ローカル名前空間で自己参照のレイジーシーケンスを作成する方法を尋ねていると思います。私は何をすべきか?

編集:私はamalloyによって投稿され、インターネット全体で見つかった人気のあるソリューションがdefn fibs [] (map first (iterate (fn [[a b]] [b (+ a b)]) [0 1])))好きですが、正規のHaskellの方法に似たバージョンに興味があります:

fibonaccis = 0 : 1 : zipWith (+) fibonaccis (tail fibonaccis)

これが私が本来の機能で達成しようとしていたことです。私にとって、map-iterateソリューションは「前の2つの要素を追加して新しい要素を作成する」のようになり、lazy-catソリューションは「最初のラグでストリームに参加する」のようになります。トップレベルの名前空間にシーケンスがない場合、どうすれば「最初のラグでストリームに参加」できますか?

4

5 に答える 5

4
(take 10 (map first (iterate (fn [[a b]]
                               [b (+ a b)])
                             [0 1])))

;; (0 1 1 2 3 5 8 13 21 34)

または、手作業でlazy-seqを使用する場合は、次のようにします。

(letfn [(fibs
          ([]
             (fibs 0 1))
          ([a b]
             (lazy-seq
               (cons a (fibs b (+ a b))))))]
  (take 10 (fibs)))

;; (0 1 1 2 3 5 8 13 21 34)
于 2012-09-25T21:39:03.187 に答える
3

fn[]の前にオプションの名前を付けると、フォームで定義された関数が再帰的になる可能性があります。(この例では、使用される名前はですthis

user> (defn fibonacci-numbers []
        ((fn this [a b] (lazy-seq (cons a (this b (+ a b))))) 0 1))

user> (take 10 (fibonacci-numbers))
(0 1 1 2 3 5 8 13 21 34)

シーケンスを生成する実際の関数は、呼び出されるたびに次の要素のみを生成する無名関数です。スタックまたはヒープオーバーフローの可能性はありません(囲んでいる関数の戻り値をvarのどこかに保持していない限り)

于 2012-09-25T21:51:52.193 に答える
1

私は非常によく似た問題を抱えていて、最終的に次のマクロを選択しました(これは基本的に約束を含むアマロイの答えよりも砂糖です):

(defmacro rec-seq [name expr]
   `(let [p# (promise)
           s# (lazy-seq (let [~name @p#] ~expr))]
       (deliver p# s#)
        s#))

これにより、次のように書くことができます。

(defn  fibonacci-numbers-fn []
   (rec-seq fibs (lazy-cat [0 1] (map +' fibs (rest fibs)))))

これはほとんどあなたが書きたかったものです。

PS:rec-seqは、recursive-seqの略です。

于 2015-08-30T22:04:27.707 に答える
0

haskellが自動的に行うことを手動で実行して、aを使用しpromiseて結び目を結ぶことができます。

(defn fibs []
  (let [fibs (promise)]
    @(doto fibs
       (deliver (list* 0 1 (lazy-seq (map +' @fibs (rest @fibs))))))))
于 2015-08-29T21:49:29.257 に答える
-1

おそらくletfnあなたが探しているものですか?

(def fibo-nums
  (letfn [(fibo-num-fn []
            (lazy-cat [0 1]
              (map + (fibo-num-fn) (rest (fibo-num-fn)))))]
    fibo-num-fn))
于 2012-09-25T20:49:50.153 に答える