2016-03-23 6 views
1

Je suis en train d'écrire un programme qui utilise des paires classiques à la fois: Common Lisp, Scheme, et al.Construire récursivement contre les listes

(deftype Cons [car cdr] 
    clojure.lang.ISeq 
    (first [c] (.car c)) 
    (more [c] (.cdr c)) 

Je crée des listes en enchaînant des cellules, par ex. (Cons. a (Cons. b nil)) pour la liste contenant a et b. J'ai écrit une fonction pour convertir une collection Clojure dans une liste de contre:

(defn conslist [xs] 
    (if (empty? xs) 
     nil 
     (Cons. (first xs) (conslist (rest xs))))) 

Cela fonctionne, mais débordera si xs est trop grand. recur ne fonctionne pas parce que l'appel récursif n'est pas dans une position de queue. L'utilisation de loop avec un accumulateur ne fonctionnerait pas, car cons met uniquement les éléments en avant, lorsque chaque recurse vous donne l'élément suivant, et je ne peux pas utiliser conj.

Que puis-je faire?

Edit: En fin de compte, si Clojure fonctionne, Clojure n'est pas conçu pour supporter les paires (vous ne pouvez pas régler le tail sur un non-SEQ). J'ai fini par créer une structure de données personnalisée et des fonctions car/cdr.

+0

Je pense que sans avoir recours à des solutions de contournement d'optimisation que vous pouvez utiliser 'loop' puis' revert' son résultat avant de le retourner. –

+0

pourriez-vous inclure un exemple d'appel à 'Cons.' qui fonctionne, avec sa sortie –

Répondre

0

lazy-seq est votre ami. Il faut un corps qui évalue à un ISeq, mais le corps ne sera pas évalué jusqu'à ce que le résultat de lazy-seq soit invoqué.

(defn conslist [xs] 
    (if (empty? xs) 
     nil 
     (lazy-seq (Cons. (first xs) (conslist (rest xs)))))) 
+0

Lorsque j'essaie d'exécuter cette solution, je reçois java.lang.AbstractMethodError –

+0

@AlanThompson J'ai raccourci la définition de' Cons' pour mon message. Vous devez implémenter 'empty'. –

+2

Utiliser quelque chose d'aussi sophistiqué que lazy-seq semble aller à l'encontre de l'objectif d'illustrer les «contre-paires classiques». – amalloy

2

comme d'habitude, je propose la plus simple boucle/RECUR:

(defn conslist [xs] 
    (loop [xs (reverse xs) res nil] 
    (if (empty? xs) 
     res 
     (recur (rest xs) (Cons. (first xs) res))))) 
+0

Cela fonctionne, mais il a spécifiquement demandé une version paresseuse. Sinon, je voudrais juste utiliser 'réduire' ou quelque chose –