I stumbled across implementation of partial function in cojure.core. It looks like this:
(defn partial
"Takes a function f and fewer than the normal arguments to f, and
returns a fn that takes a variable number of additional args. When
called, the returned function calls f with args + additional args."
{:added "1.0"
:static true}
([f] f)
([f arg1]
(fn [& args] (apply f arg1 args)))
([f arg1 arg2]
(fn [& args] (apply f arg1 arg2 args)))
([f arg1 arg2 arg3]
(fn [& args] (apply f arg1 arg2 arg3 args)))
([f arg1 arg2 arg3 & more]
(fn [& args] (apply f arg1 arg2 arg3 (concat more args)))))
Why it has several parity options if it could have one? Is it just performance optimisation so concat doesn't get called in most cases?
I mean it could look like this otherwise, right?
(defn partial
([f] f)
([f & more]
(fn [& args] (apply f (concat more args))))
)
I also noticed several other functions follow the same pattern.
Yes, it's a performance optimization.
I'ts not just about not calling concat - it's about the fact that & in the argument list requires a collection to be created as well. The clojure core libraries tend to take performance seriously, under the assumption that the basic building blocks of the language will be present in everyone's performance bottleneck.
Related
So I have a function do_stuff that can take 0 or 1 arguments as follows
(defn do_stuff
([]
(println "no arguments here"))
([arg]
(println "here's the argument"))
(defn -main
[& args]
(do_stuff (if args (apply str args))
How do I return no argument from the if statement, so that I can print the "no arguments here" string?
Edit: Using the when instead of if returns nil, which is still an argument?
Using multi-arity definitions
Apply the lesson you learned from do_stuff on -main:
(defn -main
([] (do_stuff))
([& args] (do_stuff (apply str args))))
Externalizing condition using if (or cond)
An if expression without else branch still returns nil but returning nil is not returning nothing.
That is you can't make it with an if or when expression that it just returns nothing. At least not in functional languages like Clojure is.
You could alternatively externalize your if like this:
(defn -main
[& args]
(if args
(do_stuff (apply str args))
(do_stuff)))
Using apply
#EugenePakhomov's idea:
(defn -main
[& args]
(apply do_stuff (if args [(apply str args)] [])))
But what I think is: How about to put the (apply str args) part inside do_stuff?
(defn do_stuff
([]
(println "no arguments here"))
([& args]
(let [arg (apply str args)]
(println "here's the argument"))))
Because then you could very elegantly do:
(defn -main [& args]
(apply do_stuff args))
Currently I have some code like this:
(defn compute-issue [some args] (or (age-issue some args) (name-issue some args)))
More issue types are coming.
Is there something like this:
(defn compute-issue [some args] (first-not-nil [age-issue name-issue] some args))
; Where first-not-nil would be something like
(defn first-not-nil [fs & args]
(if (empty? fs)
nil
(let [result (apply (first fs) args)]
(if (nil? result)
(recur (rest fs) args)
result))))
I'm new to Clojure. Am I reinventing an existing function?
There is a similar function some-fn in clojure.core:
Takes a set of predicates and returns a function f that returns the first logical true value
returned by one of its composing predicates against any of its arguments, else it returns
logical false. Note that f is short-circuiting in that it will stop execution on the first
argument that triggers a logical true result against the original predicates.
The key differences are some-fn returns another function for the actual function application, and that function will also discard false results, which it sounds like you may not want. This is another simple way to phrase it:
(defn first-not-nil [fs & args]
(first
(for [f fs
:let [r (apply f args)]
:when (some? r)]
r)))
This question already has an answer here:
Why such implementation of partial in clojure.core
(1 answer)
Closed 6 years ago.
I'm a beginner in clojure trying to understand it at a basic level for now.
I've been experimenting with partial and how it creates closures, and to get a deeper understanding I thought I should take a peek at the source code by doing a (source partial) .
There I get
(defn partial
"Takes a function f and fewer than the normal arguments to f, and
returns a fn that takes a variable number of additional args. When
called, the returned function calls f with args + additional args."
{:added "1.0"
:static true}
([f] f)
([f arg1]
(fn
([] (f arg1))
([x] (f arg1 x))
([x y] (f arg1 x y))
([x y z] (f arg1 x y z))
([x y z & args] (apply f arg1 x y z args))))
([f arg1 arg2]
(fn
([] (f arg1 arg2))
([x] (f arg1 arg2 x))
([x y] (f arg1 arg2 x y))
([x y z] (f arg1 arg2 x y z))
([x y z & args] (apply f arg1 arg2 x y z args))))
([f arg1 arg2 arg3]
(fn
([] (f arg1 arg2 arg3))
([x] (f arg1 arg2 arg3 x))
([x y] (f arg1 arg2 arg3 x y))
([x y z] (f arg1 arg2 arg3 x y z))
([x y z & args] (apply f arg1 arg2 arg3 x y z args))))
([f arg1 arg2 arg3 & more]
(fn [& args] (apply f arg1 arg2 arg3 (concat more args)))))
I find the whole definition to be redundant as I would only write it in a "varargs" fashion, ie the last 2 lines.
Is this a readability feature or am I missing something basic here?
It's not a readability feature but a matter of performance. Stuart Sierra explained it in Clojure Don’ts: Optional Arguments with Varargs:
Variable-arity function calls have to allocate a sequence to hold the arguments, then go through apply. Timothy Baldridge did a quick performance comparison showing that calls to a function with multiple, fixed arities can be much faster than variable-arity (varargs) function calls.
In that benchmark, the varargs version with 1 argument is around an order of magnitude slower than the multi-arity version with 1 arg, and with 3 args the difference goes up to ~ 2 orders of magnitude.
This is not to say that varargs should not be used at all: Sparsely calling a fn with varargs will probably not affect performance, but it could hit you hard when calling it from a tight loop.
I find the whole definition to be redundant as I would only write it
in a "varargs" fashion,
You are quite right. All but the varargs definition are redundant. As #nberger points out, the others are there to improve performance. You will find many such in clojure core: such as map, max, and comp.
I find myself in need a function that is similar to some-fn but combines predicates that take multiple arguments.
The new function should take a set of predicates and return a function f. The function f should return the first logical true value returned by one of its composing predicates applied to all of f's arguments, or else logical false. So I should be able to do this:
((some-fn* < >) 1 2)
=> truthy
((some-fn* < >) 1 1)
=> falsey
It's easy enough to implement:
(defn some-fn* [& fs]
(fn [& args] (loop [fs fs]
(when (seq fs)
(or (apply (first fs) args)
(recur (rest fs)))))))
But it seems like such a simple thing should already exist in clojure.core. Does it? Or is there a simpler way to achieve what I need?
You can use some:
(defn some-fn* [& ps]
(fn [& args]
(some #(apply % args) ps)))
I am discussing closure with a friend and he thinks (partial + 5) is a closure. But I think a closure is a function closing over a free variable, for example
(let [a 10]
(defn func1 [x] (+ x a))
)
then func1 is a closure. But in this case 5 is not a free variable. So which is the right answer?
partial uses a closure to make the partial function. Check out the code of partial by using (source partial) in repl and you will see that it uses closures.
(defn partial
"Takes a function f and fewer than the normal arguments to f, and
returns a fn that takes a variable number of additional args. When
called, the returned function calls f with args + additional args."
{:added "1.0"}
([f arg1]
(fn [& args] (apply f arg1 args)))
([f arg1 arg2]
(fn [& args] (apply f arg1 arg2 args)))
([f arg1 arg2 arg3]
(fn [& args] (apply f arg1 arg2 arg3 args)))
([f arg1 arg2 arg3 & more]
(fn [& args] (apply f arg1 arg2 arg3 (concat more args)))))
(partial + 5) is an anonymous function or "lambda".
Anonymous functions are often¹ called "closures" but it's an abuse of the term ; see the discussion in "What is the difference between a 'closure' and a 'lambda'?"
[¹] Maybe because in most popular languages that support them, closures and anonymous functions are created using the same language features - which renders them undistinguishable at first glance.