編集:これを書いている過程で自分の質問に対する部分的な答えを発見しましたが、簡単に改善できると思うので、とにかく投稿します。多分そこにもっと良い解決策がありますか?
let
に頼らずにフォームで再帰関数を定義する簡単な方法を探していますletfn
。let
これはおそらく不合理な要求ですが、私がこの手法を探している理由は、多くのネストされたandletfn
ステートメントを必要とする方法で相互に依存するデータと再帰関数が混在しているためです。
次のような遅延シーケンスを生成する再帰関数を書きたいと思いました (例としてフィボナッチ数列を使用)。
(let [fibs (lazy-cat [0 1] (map + fibs (rest fibs)))]
(take 10 fibs))
fibs
しかし、バインド中に独自のシンボルを使用できないのは clojure のようです。それを回避する明白な方法はletfn
(letfn [(fibo [] (lazy-cat [0 1] (map + (fibo) (rest (fibo)))))]
(take 10 (fibo)))
しかし、前に述べたように、これは多くの厄介なネストと交互のlet
andにつながりletfn
ます。
letfn
だけを使用せずにこれを行うためにlet
、U-combinator と思われるものを使用するものを作成することから始めました (今日その概念について聞いたばかりです)。
(let [fibs (fn [fi] (lazy-cat [0 1] (map + (fi fi) (rest (fi fi)))))]
(take 10 (fibs fibs)))
しかし、どのように冗長性を取り除くの(fi fi)
ですか?
この時点で、コンビネータ Q に 1 時間も苦労して少しずつビットを追加した後、自分の質問に対する答えを発見しました。
(let [Q (fn [r] ((fn [f] (f f)) (fn [y] (r (fn [] (y y))))))
fibs (Q (fn [fi] (lazy-cat [0 1] (map + (fi) (rest (fi))))))]
(take 10 fibs))
Q
再帰シーケンスを定義するために使用しているこのコンビネータは何と呼ばれていますか? 引数のない Y コンビネータのように見えますx
。それは同じですか?
(defn Y [r]
((fn [f] (f f))
(fn [y] (r (fn [x] ((y y) x))))))
YまたはQの機能を提供するclojure.coreまたはclojure.contribの別の機能はありますか? 私がしたことが慣用的だったとは想像できません...