2012-08-11 33 views
5

Załóżmy, że masz trzy funkcje liczbę operandów 1, 2 i 3, jak poniżej:Czy clojure może ocenić łańcuch mieszanych funkcji arytmetycznych i w razie potrzeby zwrócić funkcję częściową?

(defn I [x] x) 
(defn K [x y] x) 
(defn S [x y z] (x z (y z))) 

Czy clojure posiadają funkcję oceny lub idiom do oceny:

(I K S I I) as (I (K (S (I (I))))) 

przekazujących parital funkcję liczbę operandów 2?

Rozważam stworzenie makra, które może przyjmować powyższe proste definicje funkcji i rozszerzać je do funkcji wielu elementów, które mogą zwracać częściowe wyniki. Nie chciałbym tworzyć makra, jeśli istnieje już wbudowany lub idiomatyczny sposób, aby to osiągnąć.

Oto co rozbudowane makra chciałby dla powyższych funkcji:

(defn I 
    ([x] I x) 
    ([x & more] (apply (I x) more))) 

(defn K 
    ([x] (partial K x)) 
    ([x y] x) 
    ([x y & more] (apply (K x y) more))) 

(defn S 
    ([x] (partial S x)) 
    ([x y] (partial S x y)) 
    ([x y z] (x z (y z))) 
    ([x y z & more] (apply (S x y z) more))) 
+0

Po prostu znalazłem to i pomyślałem, że * może * będzie idealne dla ciebie, a jeśli nic innego, przynajmniej pomocne ... http: //alfredodinapoli.wordpress.com/2011/03/16/a-bit-of - funkcje magii i wyższego rzędu są obsługiwane/ –

Odpowiedz

5

Nie jestem pewien, czy w pełni zrozumieć, co staramy się robić, ale funkcja comp jest przydatna do wykonywania tego rodzaju "łańcuchowanie funkcji", o którym mówisz. Na przykład:

user> ((comp vec rest list) 1 2 3 4 5) 
=> [2 3 4 5] 

co jest równoważne:

user> (vec (rest (list 1 2 3 4 5))) 
=> [2 3 4 5] 

w Twoim przypadku, jeśli masz listę (I K S I I) i chcesz, aby ocenić go jako (I (K (S (I (I))))), użyłbym (reduce comp ...), ale można również użyj (apply comp ...).

user> ((reduce comp [vec rest list]) 1 2 3 4 5) 
=> [2 3 4 5] 
user> ((apply comp [vec rest list]) 1 2 3 4 5) 
=> [2 3 4 5] 

Możesz być także zainteresowany -> lub ->> makr. Makra te zagnieżdżają swoje argumenty sekwencyjnie w następnych argumentach. Makro -> zagnieździ się w pierwszej pozycji następnego wyrażenia, natomiast makro ->> zagnieździ się w ostatniej pozycji następnego wyrażenia. Jeśli "następną rzeczą" jest funkcja, obie zachowują się tak samo i tworzą wyrażenie (function nested-things-so-far) i kontynuują dalej.

Naprawdę, przykładami są najlepsze:

(-> 1 (+ 10) (- 100) inc) 
;//Expands to... 
(inc (- (+ 1 10) 100)) 
;//Evaluating in the REPL... 
user> (-> 1 (+ 10) (- 100) inc) 
=> -88 

(->> 1 (+ 10) (- 100) inc) 
;//Expands to... 
(inc (- 100 (+ 10 1))) 
;//Evaluating in the REPL... 
user> (-> 1 (+ 10) (- 100) inc) 
=> 90 

Jednak wydaje się bardziej jak chcesz coś zrobić z udziałem auto currying (chociaż znowu nie sądzę pełni rozumiem), a do tego Nie znam nic wcześniej istniejącego wbudowanego sposobu.

+0

Dziękuję również za tę odpowiedź. Zajmie mi to trochę czasu i zobaczę, czy to może uprościć to, co robię, odkąd jestem nowy w programowaniu typu clojure i seplenienie. Czasami wiem, co chcę robić, ale nie mam pojęcia, jak to się nazywa, a nawet jeśli mam dobry termin wyszukiwania, wyniki dla clojure są bardzo ograniczone. Dowiedzenie się, że to, co próbuję zrobić, może być nazywane "auto-currying", to duża pomoc. – dansalmo