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)))
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.
Clojure has closures, and closures are an excellent way to group functions (Crockford 2008) with their supporting data.
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.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With