2010-11-26 9 views
57

Ich habe eine schwere Zeit, den Unterschied zwischen rest und next in Clojure zu verstehen. The official site's page on laziness gibt an, dass die Präferenz wahrscheinlich rest sein sollte, aber es erklärt nicht wirklich den Unterschied zwischen den beiden. Kann jemand Einblick geben?Clojure: Rest gegen nächste

+3

Dieser Punkt ist keine separate Antwort wert: Was die Antworten bisher nicht vollständig explizit gemacht haben, ist, dass '()' wahr ist, während 'nil' falsch ist. So '(defn weitergehen [my-coll] (if (rest my-coll) (weitermachen (Rest my-coll)) "Beendet.")' wird für immer weitergehen - oder vielmehr, wird den Stapel überlaufen - während '(defn fortfahren [my-coll] (if (next my-coll) (weitermachen (next my-coll))" Beendet. ")" Wird beendet. (OP hat das sicher herausgefunden; ich füge diese Bemerkung für andere hinzu.) – Mars

Antwort

55

Als Seite, die Sie beschrieben verknüpft, next ist strenger als (das neue Verhalten) rest, weil es die Struktur der faulen Nachteile bewerten muss zu wissen, ob nil oder seq zurückzukehren.

rest auf der anderen Seite gibt immer eine seq, so dass nichts ausgewertet werden muss, bis Sie tatsächlich das Ergebnis rest verwenden. Mit anderen Worten, rest ist fauler als next.

+0

OK, ich denke, ich verstehe vielleicht, was du meinst. Willst du damit sagen, dass 'next' immer eine zurückgibt? cons cell, während "rest" lediglich einen ISeq (oder welchen Typ auch immer es ist) zurückgibt? –

+1

@Daniel: 'next' gibt' nil' oder einen nicht leeren 'seq' zurück.' rest' gibt immer einen 'seq' zurück, – sepp2k

+0

Also nehme ich an, dass es für einige Sequenzen eine teure Operation ist, festzustellen, ob es mehr Elemente gibt.Mit einer normalen Liste von Cons-Zellen würde ich denken, dass es trivial ist zu bestimmen, ob Sie das Ende erreicht haben Die Liste könnte jedoch mit einer trägen Sequenz (aus Lazy-Seq, vielleicht), diese Bestimmung teuer sein verstand nicht ganz, dass sich nil von der leeren Sequenz unterschied. Es hört sich so an, als ob Subsequenzen mit Rest zu schwächeren Garantien führen und daher effizienter sein können. –

27

Es ist einfach, wenn Sie diese haben:

(next '(1)) 
=> nil 

So next bei der nächsten Sache sieht und wenn die Linie kehrt nil anstelle eines leeren seq leer. Das bedeutet, dass es nach vorne schauen muss (zum ersten Punkt, den es zurückgeben würde), was es nicht völlig faul macht (vielleicht brauchen Sie den nächsten Wert nicht, aber next verschwendet die Rechenzeit, um nach vorne zu schauen).

(rest '(1)) 
=>() 

rest sieht nicht voraus und gibt nur den Rest der Seq.

Vielleicht denken Sie, warum hier sogar zwei verschiedene Dinge zu verwenden? Der Grund ist, dass Sie normalerweise wissen möchten, ob nichts mehr im Seq ist und geben Sie einfach nil zurück, aber in einigen Fällen, in denen die Leistung sehr wichtig ist und die Auswertung eines weiteren Elements eine enorme Anstrengung bedeuten kann, können Sie rest verwenden.

+7

nur um es zu Tode zu schlagen: (Rest nil) =>() – gtrak

19

next ist wie (seq (rest ...)).

rest wird das verbleibende Stück einer Sequenz zurückgeben. Wenn dieses Stück der Sequenz noch nicht realisiert wurde, erzwingt rest es nicht. Es wird dir nicht einmal sagen, ob noch mehr Elemente in der Sequenz übrig sind.

next macht das gleiche aber zwingt dann mindestens ein Element der Sequenz zu realisieren. Wenn also nextnil zurückgibt, wissen Sie, dass in der Sequenz keine Elemente mehr vorhanden sind.

2

Ich ziehe jetzt next mit reursion zu verwenden, da die Escape-Auswertung einfacher/Reiniger ist:

(loop [lst a-list] 
    (when lst 
     (recur (next lst)) 

vs

(loop [lst a-list] 
    (when-not (empty? lst) ;; or (when (seq? lst) 
     (recur (rest lst)) 

Ein Fall für rest verwendet wird, wäre aber, wenn Sie Verwenden Sie eine Sammlung als Warteschlange oder Stapel. In diesem Fall möchten Sie, dass Ihre Funktion eine leere Sammlung zurückgibt, wenn Sie den letzten Eintrag puffern oder aus der Warteschlange entfernen.