Ricerca…


introduzione

I trasduttori sono componenti componibili per l'elaborazione di dati indipendentemente dal contesto. In questo modo possono essere utilizzati per elaborare raccolte, flussi, canali, ecc. Senza conoscere le loro sorgenti di input o i sink di output.

La libreria di core Clojure è stata estesa in 1.7 in modo che la sequenza funzioni come map, filter, take, etc. restituisca un trasduttore quando viene chiamato senza una sequenza. Poiché i trasduttori sono funzioni con contratti specifici, possono essere composti utilizzando la normale funzione comp .

Osservazioni

I trasduttori consentono di controllare la pigrizia man mano che vengono consumati. Ad esempio into è desideroso come ci si aspetterebbe, ma la sequence consumerà pigramente la sequenza attraverso il trasduttore. Tuttavia, la garanzia di pigrizia è diversa. Basta la fonte per consumare un elemento inizialmente:

(take 0 (sequence (map #(do (prn '-> %) %)) (range 5)))
;; -> 0
;; => ()

O decidere se l'elenco è vuoto:

(take 0 (sequence (comp (map #(do (prn '-> %) %)) (remove number?)) (range 5)))
;; -> 0
;; -> 1
;; -> 2
;; -> 3
;; -> 4
;; => ()

Che differisce dal solito comportamento a sequenza pigra:

(take 0 (map #(do (prn '-> %) %) (range 5)))
;; => ()

Piccolo trasduttore applicato a un vettore

(let [xf (comp
           (map inc)
           (filter even?))]
  (transduce xf + [1 2 3 4 5 6 7 8 9 10]))
;; => 30

Questo esempio crea un trasduttore assegnato al xf locale e usa transduce per applicarlo ad alcuni dati. Il trasduttore aggiunge uno a ciascuno dei suoi ingressi e restituisce solo i numeri pari.

transduce è come reduce e collassa la raccolta di input su un valore singolo usando la funzione + fornita.

Questo si legge come l'ultima macro del thread, ma separa i dati di input dai calcoli.

(->> [1 2 3 4 5 6 7 8 9 10]
     (map inc)
     (filter even?)
     (reduce +))
;; => 30

Applicazione dei trasduttori

(def xf (filter keyword?))

Applica a una raccolta, restituendo una sequenza:

(sequence xf [:a 1 2 :b :c]) ;; => (:a :b :c)

Applica a una raccolta, riducendo la raccolta risultante con un'altra funzione:

(transduce xf str [:a 1 2 :b :c]) ;; => ":a:b:c"

Applica a una raccolta e conj il risultato a un'altra raccolta:

(into [] xf [:a 1 2 :b :c]) ;; => [:a :b :c]

Crea un canale asincrono principale che utilizza un trasduttore per filtrare i messaggi:

(require '[clojure.core.async :refer [chan >!! <!! poll!]])
(doseq [e [:a 1 2 :b :c]] (>!! ch e))
(<!! ch) ;; => :a
(<!! ch) ;; => :b
(<!! ch) ;; => :c
(poll! ch) ;;=> nil

Creazione / uso di trasduttori

Quindi le funzioni più utilizzate sulla mappa e sul filtro Clojure sono state modificate per restituire trasduttori (trasformazioni algoritmiche componibili), se non chiamate con una raccolta. Questo significa:

(map inc) restituisce un trasduttore e lo fa (filter odd?)

Il vantaggio: le funzioni possono essere composte in una singola funzione da comp, il che significa attraversare la raccolta una sola volta. Risparmia tempo di esecuzione di oltre il 50% in alcuni scenari.

Definizione:

(def composed-fn (comp (map inc) (filter odd?)))

Uso:

;; So instead of doing this:
(->> [1 8 3 10 5]
     (map inc)
    (filter odd?))
;; Output [9 11]

;; We do this: 
(into [] composed-fn [1 8 3 10 5])
;; Output: [9 11]


Modified text is an extract of the original Stack Overflow Documentation
Autorizzato sotto CC BY-SA 3.0
Non affiliato con Stack Overflow