2013-07-06 7 views
6

Ho eseguito in diverse situazioni in cui voglio fare una catena di operazioni su un oggetto con funzioni opzionali. "->" funziona alla grande per sequenze di comandi sullo stesso oggetto (ad esempio (c (b (a x))) diventa (-> x a b c)), tranne se alcune operazioni sono opzionali. Ad esempio, supponiamo che io volevo fare:clojure's -> (freccia) operatore e operazioni opzionali

(c 
    (if (> (a x) 2) 
    (b (a x)) 
    (a x) 
    ) 
) 

Esiste un modo per farlo in modo più chiaro con un'operazione come "->"?

risposta

10

È possibile farlo con cond->, di recente introduzione in Clojure 1.5:

(cond-> x 
    true  a 
    (> (a x) 2) b 
    true  c) 

O, meglio,

(-> x 
    a 
    (cond-> (> (a x) 2) b) 
    c) 

Significato, "prendere x, farla passare attraverso a, prendere il risultato e passalo attraverso b se (> (a x) 2) oppure lascialo invariato, finalmente prendi quello che hai e collegalo tramite c ".

In altre parole, cond-> è come ->, tranne che invece di moduli singoli per infilare l'espressione attraverso prende prova + formare coppie in cui il modulo è saltato se test è falsey e utilizzato per filettare se test è truthy:

(cond-> x 
    test-1 form-1 
    test-2 form-2) 

;; if test-1 is truthy and test-2 is falsey, output is as if from 
(-> x test-1) 

;; if it's the other way around, output is as if from 
(-> x test-2) 

;; if both tests are truthy: 
(-> x test-1 test-2) 

;; if both tests are falsey: 
x 
+3

Per inciso, 'cond->' è il mio campione personale nella Competizione più incomprensibile di Docstring. –

+1

Un'altra riformulazione: "Prende x e le clausole, interpreta le clausole come coppie di test ed expr, quindi filtra x attraverso quegli expr per i quali i test corrispondenti sono veritieri." –

+0

Pallet [thread-expr] (https://github.com/pallet/thread-expr) ha più fns simili. – noahlz