Sök…
Introduktion
Omvandlare är komponerbara komponenter för behandling av data oberoende av sammanhanget. Så de kan användas för att bearbeta samlingar, strömmar, kanaler osv. Utan kunskap om deras ingångskällor eller utgångssänkor.
Clojure-kärnbiblioteket utökades i 1,7 så att sekvensfunktionerna som karta, filter, ta, etc. returnerar en givare när den kallas utan en sekvens. Eftersom givare är funktioner med specifika kontrakt kan de komponeras med den normala comp
.
Anmärkningar
Omvandlare gör att latskapen kan kontrolleras när de konsumeras. Till exempel into
är ivriga som man kunde förvänta sig, men sequence
förbrukar lata sekvensen genom givaren. Dock är lathetsgarantin annorlunda. Tillräckligt med källan kommer att konsumeras för att producera ett element initialt:
(take 0 (sequence (map #(do (prn '-> %) %)) (range 5)))
;; -> 0
;; => ()
Eller bestäm om listan är tom:
(take 0 (sequence (comp (map #(do (prn '-> %) %)) (remove number?)) (range 5)))
;; -> 0
;; -> 1
;; -> 2
;; -> 3
;; -> 4
;; => ()
Vilket skiljer sig från det vanliga lata sekvensbeteendet:
(take 0 (map #(do (prn '-> %) %) (range 5)))
;; => ()
Liten givare applicerad på en vektor
(let [xf (comp
(map inc)
(filter even?))]
(transduce xf + [1 2 3 4 5 6 7 8 9 10]))
;; => 30
Detta exempel skapar en givare tilldelad den lokala xf
och använder transduce
att tillämpa den på vissa data. Givarens tillägg är en till var och en av sina ingångar och ger bara de jämna siffrorna.
transduce
är som reduce
och kollapsar insamlingssamlingen till ett enda värde med den medföljande +
-funktionen.
Detta läser som tråd-sista makro, men skiljer inmatningsdata från beräkningarna.
(->> [1 2 3 4 5 6 7 8 9 10]
(map inc)
(filter even?)
(reduce +))
;; => 30
Applicera givare
(def xf (filter keyword?))
Ansök om en samling och returnera en sekvens:
(sequence xf [:a 1 2 :b :c]) ;; => (:a :b :c)
Applicera på en samling, minska den resulterande samlingen med en annan funktion:
(transduce xf str [:a 1 2 :b :c]) ;; => ":a:b:c"
Applicera på en samling och conj
resultatet till en annan samling:
(into [] xf [:a 1 2 :b :c]) ;; => [:a :b :c]
Skapa en central async-kanal som använder en givare för att filtrera meddelanden:
(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
Skapa / använda givare
Så de mest använda funktionerna på Clojure-karta och filter har modifierats för att returnera givare (komposerbara algoritmiska transformationer), om de inte kallas med en samling. Det betyder:
(map inc)
returnerar en givare och det gör (filter odd?)
Fördelen: funktionerna kan komponeras till en enda funktion med komp, vilket betyder att korsa samlingen bara en gång. Sparar körtiden med över 50% i vissa scenarier.
Definition:
(def composed-fn (comp (map inc) (filter odd?)))
Användande:
;; 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]