Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Function arguments multiple types

Tags:

clojure

I am trying to delay various calculations. I have functions of the following form,

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

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

this allows me to pass a-fn, a value or a function that returns the value,

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

what I do is build a list of functions (like the one above) to operate on some data, fns may use other fns to retrieve their arguments or in some cases things don't change and they are assigned values as arguments. I was wondering is there a better way to achive this kind of behavior?

like image 591
Hamza Yerlikaya Avatar asked Sep 07 '11 15:09

Hamza Yerlikaya


2 Answers

You can use delay and 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

If you try something like (delay (prn :hello) 1) to test when the computation is done, note that printing the Delay object forces it; so (def x (delay ...)) is safe, but typing a plain (delay ...) in the REPL prompt is not.

like image 86
Jouni K. Seppänen Avatar answered Oct 11 '22 21:10

Jouni K. Seppänen


There might be a more elegant way to do what you want, but here's at least a more generic version of it:

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

(def a-fn (partial delayed +))

So delayed takes an arbitrary function and a list of function/values. If expands all the args and then applies the function to them. Then we use partial to define your a-fn using +:

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

Alternatively, it might make sense for delayed to return a function rather than using partial. Note sure which is better.

A better name than "delayed" is welcome :)

like image 45
Dave Ray Avatar answered Oct 11 '22 21:10

Dave Ray