Clojure Partial Clarification

I read a book on clojure, and I came up with an example that I do not fully understand.

Here is the code in repl:

user=> (repeatedly 10 (rand-int 10)) ClassCastException java.lang.Integer cannot be cast to clojure.lang.IFn clojure.core/repeatedly/fn--4705 (core.clj:4642) user=> (repeatedly 10 (partial rand-int 10)) (5 0 5 5 2 4 8 8 0 0) 

My question is: why is partial needed here, and how does this relate to the definition of partial and repeatedly definition and syntax. Partially...

 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. 

So how does this fit in?

+7
source share
2 answers

partial does not actually check which arities its first argument supports; perhaps a more accurate docstring will say that it "takes a function f and some arguments in f". (It is clear that if you put too many arguments, the resulting partially applied function will be violated, although this will only be observed when trying to call it.) Therefore, why (partial rand-int 10) is fine, although the number of arguments in rand-int not is "less than normal."

The reason why partial or something like #(rand-int 10) is required is because repeatedly expects its final argument to be a function that it can call multiple times, while (rand-int 10) will be a number .

Contrast this with repeat , which returns a sequence with an included element repeated the specified number of times (or infinitely many times in the unary case). Here (rand-int 10) would be a suitable second argument, but of course it would be some specific number, so the result would look like (8 8 8 8 8 ...) ; repeatedly will make a separate call (partial rand-int 10) for each element of the returned sequence, so you get a sequence of (likely different, independent) random numbers from it.

+6
source

Partial is just an easier way to define an anonymous function that captures some arguments to the function and then passes the rest of the arguments to the created function.

In this case

 user> (repeatedly 10 (partial rand-int 10)) (3 1 3 6 1 2 7 1 5 3) 

equivalent to:

 user> (repeatedly 10 #(rand-int 10)) (9 5 6 0 0 5 7 6 9 6) 

Partial is wrong here, because partial used to correct in advance all the arguments (or rather, the only one) for rand-int.

a more interesting use of a partial illustration shows that a function is better:

 (partial + 4) 

gives the equivalent:

 (fn [& unfixed-args] (apply + (concat [4] unfixed-args))) 

(this does not literally do this) The idea is to build a function that accepts non-fixed arguments, combines them with fixed ones and calls the function you passed partial with enough arguments to work correctly.

 user> ((fn [& unfixed-args] (apply + (concat [4] unfixed-args))) 5 6 7 8 9) 39 user> ((partial + 4) 5 6 7 8 9) 39 

I use only partial in practice when the number of arguments is variable. Otherwise, I have a personal preference for using the anonymous form of reading functions #( ... )

+10
source

All Articles