Szukaj…


Wprowadzenie

Przetworniki są komponowalnymi komponentami do przetwarzania danych niezależnie od kontekstu. Dzięki temu można ich używać do przetwarzania kolekcji, strumieni, kanałów itp. Bez znajomości ich źródeł wejściowych lub odbiorników wyjściowych.

Biblioteka rdzenia Clojure została rozszerzona w wersji 1.7, dzięki czemu funkcje sekwencji, takie jak mapowanie, filtrowanie, pobieranie itp. Zwracają przetwornik, gdy są wywoływane bez sekwencji. Ponieważ przetworniki są funkcjami o określonych kontraktach, można je komponować przy użyciu normalnej funkcji comp .

Uwagi

Przetworniki pozwalają kontrolować lenistwo podczas ich konsumpcji. Na przykład into jest chętny, jak można się spodziewać, ale sequence leniwie zużywa sekwencję przez przetwornik. Jednak gwarancja lenistwa jest inna. Dość źródła zostanie zużyte na początkowy element:

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

Lub zdecyduj, czy lista jest pusta:

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

Który różni się od zwykłego zachowania leniwej sekwencji:

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

Mały przetwornik zastosowany do wektora

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

Ten przykład tworzy przetwornik przypisany do lokalnego xf i używa transduce do zastosowania go do niektórych danych. Przetwornik dodaje jeden do każdego z wejść i zwraca tylko liczby parzyste.

transduce jest jak reduce i zwija kolekcję danych wejściowych do pojedynczej wartości za pomocą dostarczonej funkcji + .

Odczytuje to jak makro ostatniego wątku, ale oddziela dane wejściowe od obliczeń.

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

Zastosowanie przetworników

(def xf (filter keyword?))

Zastosuj do kolekcji, zwracając sekwencję:

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

Zastosuj do kolekcji, zmniejszając wynikową kolekcję za pomocą innej funkcji:

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

Zastosuj do kolekcji i conj wynik w inną kolekcję:

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

Utwórz główny kanał asynchroniczny, który używa przetwornika do filtrowania wiadomości:

(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

Tworzenie / używanie przetworników

Dlatego najczęściej używane funkcje na mapie Clojure i filtrze zostały zmodyfikowane, aby zwracały przetworniki (składane transformacje algorytmiczne), jeśli nie zostały wywołane z kolekcją. To znaczy:

(map inc) zwraca przetwornik, podobnie jak (filter odd?)

Zaleta: funkcje można połączyć w jedną funkcję przez comp, co oznacza, że przemierza się kolekcję tylko raz. Oszczędza czas pracy o ponad 50% w niektórych scenariuszach.

Definicja:

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

Stosowanie:

;; 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
Licencjonowany na podstawie CC BY-SA 3.0
Nie związany z Stack Overflow