Editar : Ich habe beim Schreiben dieses Artikels eine Teilantwort auf meine eigene Frage gefunden, aber ich denke, sie kann noch verbessert werden, also werde ich sie trotzdem veröffentlichen. Vielleicht gibt es da draußen eine bessere Lösung?
Ich suche nach einer einfachen Möglichkeit, rekursive Funktionen in einer let
Form ohne Rückgriff auf letfn
. Dies ist wahrscheinlich eine unvernünftige Anfrage, aber der Grund, warum ich nach dieser Technik suche, ist, weil ich eine Mischung aus Daten und rekursiven Funktionen habe, die voneinander abhängig sind, so dass eine Menge verschachtelter let
et letfn
Erklärungen.
Ich wollte die rekursiven Funktionen schreiben, die faule Sequenzen wie diese erzeugen (am Beispiel der Fibonacci-Folge):
(let [fibs (lazy-cat [0 1] (map + fibs (rest fibs)))]
(take 10 fibs))
Aber es scheint in Clojure, dass fibs
kann sein eigenes Symbol während der Bindung nicht verwenden. Der offensichtliche Weg, dies zu umgehen, ist die Verwendung von letfn
(letfn [(fibo [] (lazy-cat [0 1] (map + (fibo) (rest (fibo)))))]
(take 10 (fibo)))
Aber wie ich bereits sagte, führt dies zu einer Menge umständlicher Verschachtelungen und abwechselnder let
et letfn
.
Um dies zu tun, ohne letfn
und nur mit let
Ich habe damit begonnen, etwas zu schreiben, das meiner Meinung nach den U-Kombinator verwendet (ich habe erst heute von diesem Konzept gehört):
(let [fibs (fn [fi] (lazy-cat [0 1] (map + (fi fi) (rest (fi fi)))))]
(take 10 (fibs fibs)))
Aber wie wird man die Redundanz von (fi fi)
?
An diesem Punkt entdeckte ich die Antwort auf meine eigene Frage, nachdem ich mich eine Stunde lang abgemüht und schrittweise Bits zum Kombinator Q hinzugefügt hatte.
(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))
Was ist das? Q
Kombinator genannt, den ich zur Definition einer rekursiven Folge verwende? Es sieht aus wie der Y-Kombinator ohne Argumente x
. Ist es dasselbe?
(defn Y [r]
((fn [f] (f f))
(fn [y] (r (fn [x] ((y y) x))))))
Gibt es eine andere Funktion in clojure.core oder clojure.contrib, die die Funktionalität von Y oder Q bietet? Ich kann mir nicht vorstellen, dass das, was ich gerade getan habe, idiomatisch war...