2016-05-04 5 views
1

Ich bin neu in Clojure und Lisp, aber liebe es so weit. Ich versuche derzeit, die Fähigkeit von Lazy-Seq und Clojure zu verstehen, unendliche Sequenzen zu definieren. Ich habe den folgenden Code:Anfänger Clojurist Lazy Sequenzfehler: Ich weiß nicht, wie man ISeq erstellt von: java.lang.Long

(defn geometric 
    ([] geometric 1) 
    ([n] (cons n (lazy-seq (geometric (* n 1/2)))))) 

Wenn ich laufen:

(geometric) 

in meinem REPL, es gibt 1 zurück, wie erwartet. Allerdings, wenn ich laufen,

(take 10 (geometric)) 

bekomme ich folgende Fehlermeldung:

IllegalArgumentException Don't know how to create ISeq from: 
java.lang.Long clojure.lang.RT.seqFrom 

Was erwarte ich zu bekommen ist:

(1 1/2 1/4 1/8 1/16 1/32 1/64 1/128 1/256 1/512) 

Warum bin ich diesen Fehler? Wenn ich richtig verstanden habe, sollte man in der Lage sein, die Lazy-Sequenz zu konsumieren, und Take sollte die ersten zehn Werte der Sequenz zurückgeben, die rekursiv ausgewertet werden.

Antwort

2

Sie haben einen kleinen Tippfehler in Ihrem Code:

(defn geometric 
    ([] (geometric 1)) ;; notice the added parens around geometric 1 
    ([n] (cons n (lazy-seq (geometric (* n 1/2)))))) 

Ohne dieses Update (geometric 1) arbeitet, weil die Umsetzung Ausdruck geometric (nur ein Funktionswert) zu bewerten war, die verworfen wurde, dann wurde 1 Ausdruck ausgewertet und zurückgegeben als das Funktionsergebnis (es war der letzte Ausdruck in diesem Arity-Funktionskörper).

Jetzt funktioniert es wie erwartet:

(take 1 (geometric)) 
;; => (1) 

(take 5 (geometric)) 
;; => (defn geometric 
    ([] geometric 1) 
    ([n] (cons n (lazy-seq (geometric (* n 1/2)))))) 

Beachten Sie, dass Sie nicht nur (geometric) sicher in REPL nennen kann, wie sie versuchen, eine unendliche Folge zu bewerten.

1

(geometric) wertet die Nummer 1 aus, nicht zu einer Sequenz. (take 10 1) gibt den gleichen Fehler, den Sie jetzt sehen.

Sie sollten versuchen, (take 10 (geometric 1)) auszuführen, da (geometric 1) eine Sequenz erzeugt, die an das zweite Argument von take geliefert werden kann.

2

Ihr Problem ist hier:

([] geometric 1) 

Dieser Ausdruck bedeutet, dass, wenn geometric ohne Argumente aufgerufen wird, passieren zwei Dinge:

  1. Das Symbol geometric ausgewertet werden, die wird die geometric Funktion ergeben.
  2. Die Nummer 1 wird zurückgegeben.

Was Sie wahrscheinlich gemeint war:

([] (geometric 1)) 

Das bedeutet, dass der Aufruf (geometric 1)(geometric) entsprechen aufrufe. Ihr Beispiel wird nun wie erwartet:

(take 10 (geometric)) 
;=> (1 1/2 1/4 1/8 1/16 1/32 1/64 1/128 1/256 1/512) 
4

Eine meiner Lieblingsfunktionen: iterate nimmt eine Funktion f und einen Wert x Rückkehr x, (f x), (f (f x), (f (f (f x))) usw.

Hier ist eine elegante Implementierung mit der gleichen Funktionalität:

(defn geometric [] 
    (iterate #(/ % 2) 1)) 

Keine direkte Antwort auf Ihre Frage, aber hoffentlich informativ!