Modifier: J'ai découvert une réponse partielle à ma propre question en écrivant ceci, mais je pense qu'elle peut facilement être améliorée, donc je vais quand même la publier. Peut-être qu'il existe une meilleure solution ?
Je cherche un moyen facile de définir des fonctions récursives dans une forme let
sans avoir recours à letfn
. C'est probablement une demande déraisonnable, mais la raison pour laquelle je cherche cette technique est que j'ai un mélange de données et de fonctions récursives qui dépendent les unes des autres de manière à nécessiter beaucoup d'assertions let
et letfn
imbriquées.
Je voulais écrire les fonctions récursives qui génèrent des séquences paresseuses de cette manière (en utilisant la séquence de Fibonacci comme exemple) :
(let [fibs (lazy-cat [0 1] (map + fibs (rest fibs)))]
(take 10 fibs))
Mais il semble qu'en clojure, fibs
ne peut pas utiliser son propre symbole pendant la liaison. La manière évidente de contourner cela est d'utiliser letfn
.
(letfn [(fibo [] (lazy-cat [0 1] (map + (fibo) (rest (fibo)))))]
(take 10 (fibo)))
Mais comme je l'ai dit plus tôt, cela conduit à beaucoup d'imbrications gênantes et d'alternance entre let
et letfn
.
Pour faire cela sans letfn
et en utilisant simplement let
, j'ai commencé par écrire quelque chose qui utilise ce que je pense être le U-combinateur (je viens de découvrir le concept aujourd'hui) :
(let [fibs (fn [fi] (lazy-cat [0 1] (map + (fi fi) (rest (fi fi)))))]
(take 10 (fibs fibs)))
Mais comment se débarrasser de la redondance de (fi fi)
?
C'est à ce moment-là que j'ai découvert la réponse à ma propre question après une heure de lutte et d'ajout progressif de morceaux au combinateur Q.
(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))
Comment s'appelle ce combinateur Q
que j'utilise pour définir une séquence récursive ? On dirait le combinateur Y sans arguments x
. Est-ce la même chose ?
(defn Y [r]
((fn [f] (f f))
(fn [y] (r (fn [x] ((y y) x))))))
Y a-t-il une autre fonction dans clojure.core ou clojure.contrib qui fournit la fonctionnalité de Y ou Q ? Je ne peux pas imaginer que ce que je viens de faire soit idiomatique...