2011-09-07 29 views
6

Próbuję opóźnić różne obliczenia. Mam funkcje poniższego formularza,Argumenty funkcji wiele typów

(defn a-fn [a b] 
    (let [a (if (fn? a) 
      a 
      #(identity a)) 

     b (if (fn? b) 
      b 
      #(identity b))] 
    (+ (a) (b)))) 

to pozwala mi przejść a-fn wartość lub funkcja, która zwraca wartość,

(a-fn 1 2)  
(defn x [] 1)  
(defn y [] 2)  
(a-fn x y) 
(a-fn x 2) 

co mogę zrobić, to zbudować listę funkcji (jak ten powyżej) do operowania na niektórych danych, fns mogą używać innych fns do pobierania swoich argumentów lub w niektórych przypadkach rzeczy się nie zmieniają i są one przypisywane wartościom jako argumenty. Zastanawiam się, czy istnieje lepszy sposób na osiągnięcie tego rodzaju zachowania?

Odpowiedz

2

Nie może być bardziej elegancki sposób, aby robić to, co chcesz, ale tu przynajmniej bardziej rodzajowy wersja to:

(defn delayed [reducer & fs] 
    (apply reducer (for [f fs] (if (fn? f) (f) f)))) 

(def a-fn (partial delayed +)) 

Więc delayed wykonuje dowolną funkcję oraz listę funkcji/wartości. Jeśli rozszerzy wszystkie argumenty, a następnie zastosuje do nich funkcję. Następnie używamy partial zdefiniować a-fn użyciu +:

user=> (a-fn 1 2) 
3 
user=> (a-fn (constantly 1) 2) 
3 
user=> (a-fn (constantly 1) 2 4) 
7 

Alternatywnie, może to mieć sens dla delayed aby powrócić do funkcji zamiast używać częściowe. Zwróć uwagę, co jest lepsze.

lepszej nazwy niż „opóźniony” jest mile widziany :)

6

Można użyć delay i force:

user=> (defn a-fn [a b] (+ (force a) (force b))) 
#'user/a-fn 
user=> (a-fn 1 2) 
3 
user=> (def x (delay 1)) 
#'user/x 
user=> (def y (delay 2)) 
#'user/y 
user=> (a-fn x y) 
3 
user=> (a-fn x 2) 
3 

Jeśli próbujesz coś jak (delay (prn :hello) 1) przetestować gdy obliczanie odbywa, trzeba pamiętać, że drukowanie obiekt opóźnienia wymusza to; więc (def x (delay ...)) jest bezpieczny, ale wpisanie zwykłego (delay ...) w wierszu REPL nie jest prawidłowe.

+0

Nice. Zapomniałem o opóźnieniu/sile. –