Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can clojure evaluate a chain of mixed arity functions and return a partial function if needed?

Suppose you have three functions of arity 1, 2 and 3 as below:

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

Does clojure have an evaluation function or idiom for evaluating:

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

returning a parital function of arity 2?

I am considering creating a macro that can take the simple function definitions above and expand them to multi-arity functions that can return partial results. I would not want to create the macro if there is already a built in or idiomatic way to accomplish this.

Here is what the expanded macros would like for the above functions:

(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)))
like image 294
dansalmo Avatar asked Aug 11 '12 23:08

dansalmo


People also ask

What is partial Clojure?

Clojure therefore has the partial function gives results similar to currying, however the partial function also works with variable functions. partial refers to supplying some number of arguments to a function, and getting back a new function that takes the rest of the arguments and returns the final result.

Does Clojure have closures?

Clojure has closures, and closures are an excellent way to group functions (Crockford 2008) with their supporting data.

How do you create a function in Clojure?

A function is defined by using the 'defn' macro. An anonymous function is a function which has no name associated with it. Clojure functions can be defined with zero or more parameters. The values you pass to functions are called arguments, and the arguments can be of any type.


1 Answers

I'm not sure I fully understand what you are trying to do, but the comp function is useful for doing this kind of "function chaining" you seem to be talking about. For example:

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

Which is equivalent to:

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

In your case, if you have the list (I K S I I), and you want to evaluate it as (I (K (S (I (I))))), I would use (reduce comp ...), but you could also use (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]

You may also be interested in the -> or ->> macros. These macros nest their arguments sequentially into the next arguments. The -> macro will nest into the first position of the next expression, whereas the ->> macro will nest into the last position of the next expression. If the "next thing" is a function, both will behave the same, and form an expression of (function nested-things-so-far), and continue along.

Really, examples are best:

(-> 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

However, it seems more like you want to do something involving auto-currying (although, again, I don't think I fully understand), and for that I don't know of anything pre-existing built-in way.

like image 179
Omri Bernstein Avatar answered Sep 23 '22 19:09

Omri Bernstein