2016-03-23 10 views
1

Ich schreibe ein Programm, das klassische Contra-Paare a la Common Lisp, Scheme, et al. Verwendet.Rekursiv Listen aufbauen

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

Ich erstelle Listen durch Verkettung von Cons-Zellen, z.B. (Cons. a (Cons. b nil)) für die Liste mit a und b. Ich schrieb eine Funktion, um eine Clojure Sammlung in eine cons Liste zu konvertieren:

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

Das funktioniert aber überlaufen, wenn xs zu groß ist. recur funktioniert nicht, da der rekursive Aufruf nicht in einer Endposition ist. Die Verwendung von loop mit einem Akku würde nicht funktionieren, weil cons nur Zeug an der Vorderseite, wenn jede Rekursion gibt Ihnen die nächste Artikel, und ich kann nicht conj verwenden.

Was kann ich tun?

Edit: Am Ende stellt sich heraus, wenn Sie dies funktioniert, ist Clojure grundsätzlich nicht entworfen, um Cons-Paare zu unterstützen (Sie können den Schwanz nicht auf eine Nicht-Seq setzen). Ich habe am Ende nur eine benutzerdefinierte Datenstruktur und Auto/CDR-Funktionen erstellt.

+0

Ich denke, ohne auf einige Optimierungs Abhilfen greifen Sie 'loop' verwenden können und dann' revert' das Ergebnis, bevor er zurückkehrt. –

+0

könnten Sie einen Beispielaufruf zu 'Cons.' einschließen, der zusammen mit seiner Ausgabe funktioniert –

Antwort

0

lazy-seq ist dein Freund hier. Es braucht einen Körper, der zu einem ISeq auswertet, aber der Körper wird nicht ausgewertet, bis das Ergebnis lazy-seq aufgerufen wird.

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

Wenn ich versuche, diese Lösung auszuführen, bekomme ich java.lang.AbstractMethodError –

+0

@AlanThompson Ich habe die Definition von' Cons' für meinen Beitrag gekürzt. Sie müssen "leer" implementieren. –

+2

Die Verwendung von etwas so raffiniert wie Lazy-Seq scheint den Zweck zu besiegen, "klassische Nachteile" zu illustrieren. – amalloy

2

wie üblich, ich würde die einfachste Schleife/recur schlagen:

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

Das funktioniert, aber er fragte speziell nach einer faulen Version. Ansonsten würde ich nur 'reduce' oder so etwas verwenden –