2009-11-06 6 views
4

Je suis à la recherche d'une façon propre et idiomatique de faire une "réduction en arrière" dans Clojure.Réduit un ensemble de fonctions sur une valeur?

J'ai

(def fns '(fn1 fn2 fn3)) 
(def val 42) 

Je voudrais obtenir (fn3 (fn2 (fn1 val))), et je ne suis pas pointilleux sur l'ordre. Donc, je voudrais appliquer consécutivement une séquence de fonctions à une valeur, plutôt que consécutivement une séquence de valeurs à une fonction.

Suggestions? Merci!

Répondre

5

Encore une autre façon de penser est une composition de fonctions:

user=> ((apply comp [inc dec inc]) 42) 
43 
+1

J'aime cette solution, mais je pense inverser la collection de fonctions. '((comp f1 f2 f3) x)' évalue à '(f1 (f2 (f3 x)))' et le demandeur le voulait dans l'autre sens. – Jonas

+0

Tout à fait raison. La question indiquait: «Je ne suis pas pointilleux sur la commande», ce que j'ai pris pour signifier soit qu'ils étaient commutatifs ou pourraient être arrangés de toute façon. Cependant, pour certaines fonctions, l'ordre est très important ((appliquer comp [/ +]) 1 2) -> 1/3 ;;; ((applique comp (reverse [/ +])) 1 2) -> 1/2 –

+0

J'aime vraiment cette solution aussi, elle s'est retrouvée dans mon code. Merci! – Dan

3

Je ne suis pas un utilisateur Clojure très avancé non plus, donc le langage de la description de l'API a tendance à me paraître un peu laconique et cryptique. Mais compte tenu de ma compréhension limitée, la macro "->" a frappé mon oeil. Il «enfile» une valeur x à travers une série de «formes», ce qui me semble étrangement similaire à ce que vous recherchez.

Comme c'est une macro, je ne sais pas si vous pouvez utiliser (appliquer) pour l'insérer dans votre liste de fn, mais je vais essayer!

+0

Mes sources de sagesse: http://clojure.org/api#toc35 et http://clojure.org/cheatsheet. –

+0

Comme c'est une macro, vous devez définir une autre macro à utiliser. – cobbal

+1

(defmacro back-thread [val, fns] '(-> ~ val ~ @ fns)) – cobbal

1

... Que diriez-vous

(defn back-reduce 
([firstfunction restfunctions val] 
    (if (= restfunctions nil) 
     (firstfunction val) 
     (back-reduce (car restfunctions) (cdr restfunctions) (firstfunction val)) 
    ) 
)) 
+0

hmmmm ne ressemble pas au code Clojure car il a "voiture" et "cdr" :-) – mikera

7

Ceci est tout simplement réduire. Rappelez-vous que les fonctions sont aussi des objets. En outre, vous appliquez toujours vos fonctions afin f1, f2 puis, etc. Ne pas confondre avec le fait qu'il lit (f4 (f3 ...

Donc il suffit d'utiliser régulièrement réduire.

(reduce #(%2 %1) val functions) 
+0

Merci beaucoup! BTW, j'ai remarqué que (def fns '(fn1 fn2 fn3)) ne fonctionne pas ici, il est nécessaire d'utiliser (def fns [#' fn1 # 'fn2 #' fn3]) – Dan

+0

fonctionne! brillant! (réduire # (% 2% 1) 42 [inc dec inc]) => 43 –

+0

caffeine.cc: Une liste entre guillemets vous donne des symboles plutôt que les valeurs (fonctions) auxquelles les symboles évaluent; c'est tout l'intérêt de citer quelque chose. Vous auriez pu faire '(liste fn1 fn2 fn3)' ou '[fn1 fn2 fn3]'; la version vectorielle est plus idiomatique dans Clojure. –

2

manière la plus simple écrire dans Clojure serait:

((comp fn3 fn2 fn1) 42) 
Questions connexes