2012-04-06 6 views
2

In a question über eine Funktion zu beantworten, die mehrere Funktionen mit den gleichen Argumenten Karten über (A: juxt), kam ich mit einer Funktion auf, die im Wesentlichen die gleiche Form wie juxt nahmen, aber Karte verwendet:Irgendwelche Vorteile für eine lazy-ish juxt-Funktion?

(defn could-be-lazy-juxt 
    [& funs] 
    (fn [& args] 
    (map apply funs (repeat args)))) 

=> ((juxt inc dec str) 1) 
[2 0 "1"] 
=> ((could-be-lazy-juxt inc dec str) 1) 
(2 0 "1") 

=> ((juxt */-) 6 2) 
[12 3 4] 
=> ((could-be-lazy-juxt */-) 6 2) 
(12 3 4) 

I Ich habe wenig Ahnung von der Faulheit oder der Leistung, aber das Timing in der REPL deutet darauf hin, dass etwas Faules vor sich geht.

=> (time (apply (juxt + -) (range 1 100))) 
"Elapsed time: 0.097198 msecs" 
[4950 -4948] 
=> (time (apply (could-be-lazy-juxt + -) (range 1 100))) 
"Elapsed time: 0.074558 msecs" 
(4950 -4948) 

=> (time (apply (juxt + -) (range 10000000))) 
"Elapsed time: 1019.317913 msecs" 
[49999995000000 -49999995000000] 
=> (time (apply (could-be-lazy-juxt + -) (range 10000000))) 
"Elapsed time: 0.070332 msecs" 
(49999995000000 -49999995000000) 

Ich bin sicher, dass diese Funktion nicht wirklich schnell ist (der Druck des Ergebnisses ‚fühlt‘ etwa so lang in beide). Ein "Take x" auf der Funktion begrenzt nur die Menge der evaluierten Funktionen, was wahrscheinlich in ihrer Anwendbarkeit begrenzt ist, und das Begrenzen der anderen Parameter durch "Take" sollte in normalem juxt genauso faul sein.

Ist das juxt wirklich faul? Würde ein lazy juxt etwas Nützliches an den Tisch bringen, zum Beispiel als einen Kompositionsschritt zwischen anderen faulen Funktionen? Was sind die Auswirkungen auf die Leistung (mem/cpu/Objektanzahl/Kompilierung)? Warum wird der Clojure juxt mit einem Reduzieren implementiert und gibt einen Vektor zurück, der Faulheit bricht?

+0

Beachten Sie, dass '' realisiert '' Funktion, ob ein faules-Seq zu identifizieren hilft (unter? andere) hat einen Wert erzeugt. z.B. '(realisiert? ((könnte sein-lazy-juxt inc dec str) 1)))' '=>' 'false'' – sw1nn

+0

Ich glaube, du könntest auch einfach' apply' für '# ersetzen (bewerbe% 1% 2) 'in Ihrem ersten Beispiel. –

+0

Sie sind völlig richtig, danke! Scheint "Dinge können in Clojure immer einfacher gemacht werden" steht noch;) – NielsK

Antwort

1

Ja, Ihre Implementierung von juxt ist faul, weil Sie nur map aufrufen, die faul ist.

es ist schwer, es zu nennen darin mit aus jetziger Form ist anwenden, um die Argumente in dem Anrufer zu realisieren (durch die Verwendung so eine Folge von Funktionen nehme ich es ein wenig verändert.

user> (defn could-be-lazy-juxt 
    [funs] 
    (fn [& args] 
    (map #(apply %1 %2) funs (repeat args)))) 
#'user/could-be-lazy-juxt 

dann ein faulen definieren Folge von Funktionen, die eine Menge Ausgabe machen, wenn es

user> (defn loud-seq [len] (take len (map #(do (println "produced a function") %) (cycle [inc dec])))) 
#'user/loud-seq 

dann juxt realisiert ist verwenden, um eine Funktion aus dieser faulen Folge von Funktionen zu machen

user> (def f (could-be-lazy-juxt (loud-seq 50))) 
#'user/f 

wie Sie sehen können, ist die Liste immer noch faul, es realisiert, dass es eine Liste von Funktionen ist, wenn es die resultierende Funktion aufgerufen wird.

läßt es so nennen:

user> (f 1) 
(produced a function 
produced a function 
2 produced a function 
produced a function 
0 2 produced a function 
produced a function 
0 2 produced a function 
produced a function 
0 2 produced a function 
produced a function 
0 2 produced a function 
produced a function 
0 2 produced a function 
produced a function 
0 2 produced a function 
produced a function 
0 2 produced a function 
produced a function 
0 2 produced a function 
produced a function 
0 2 produced a function 
produced a function 
0 2 produced a function 
produced a function 
0 2 produced a function 
produced a function 
0 2 produced a function 
produced a function 
0 2 produced a function 
produced a function 
0 2 produced a function 
produced a function 
0 2 produced a function 
produced a function 
0 2 produced a function 
produced a function 
0 2 produced a function 
produced a function 
0 2 produced a function 
produced a function 
0 2 produced a function 
produced a function 
0 2 produced a function 
produced a function 
0 2 produced a function 
produced a function 
0 2 produced a function 
produced a function 
0 2 produced a function 
produced a function 
0 2 0) 
user> 

ich die Gründe dafür an Sie lassen;)

+0

Ein Vorbehalt allerdings: Lazy Seqs sind nicht faul eins nach dem anderen, sondern Stück für Stück (chunked-seq). Siehe zum Beispiel [hier] (http://blog.fogus.me/2010/01/22/de-chunkifying-sequences-in-clojure/). Dies kann sehr relevant sein, wenn Ihr Lazy Seq aus beliebigen Funktionsaufrufen besteht. –

+0

Danke, dass du das gezeigt hast! Chunking wird leicht übersehen. –

Verwandte Themen