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.
user=> (def to-english (partial clojure.pprint/cl-format nil "~@(~@[~R~]~^ ~A.~)")) #'user/to-english user=> (to-english 1234567890) "One billion, two hundred thirty-four million, five hundred sixty-seven thousand, eight hundred ninety"
user=> (def hundred-times (partial * 100)) #'user/hundred-times user=> (hundred-times 5) 500 user=> (hundred-times 4 5 6) 12000 user=> (def add-hundred (partial + 100)) #'user/add-hundred user=> (add-hundred 5) 105
(def subtract-from-hundred (partial - 100)) user=> (subtract-from-hundred 10) ; same as (- 100 10) 90 user=> (subtract-from-hundred 10 20) ; same as (- 100 10 20) 70
; Maps exponent to coefficient ; x^3 + 2x + 1 (def poly (fn [n] (cond (= 0 n) 1 (= 1 n) 2 (= 3 n) 1 :else 0))) ; Differentiates input by returning a polynomial that is curried ; 3x^2 + 2 (defn diff [p] (partial (fn [p n] (* (+ 1 n) (p (+ 1 n)))) p)) (poly 3) ;=> 1 ((diff poly) 3) ;=> 0 ((diff poly) 2) ;=> 3
user=> (defn fun-full [x y] (+ x y)) ;=> #<function user$fun_full(x,y){ ... user=> (fun-full 2 3) ;=> 5 user=> (def fun-half (partial fun-full 2)) ;=> #<function (x,y,z,var_args){ ... user=> (fun-half 3) ;=> 5
;;Takes a function f and the normal full arguments is allowed user=> (defn add [x y] (+ x y)) #'user/add user=> (partial add 1 1 ) #object[clojure.core$partial$fn__4529 0x5eb8fe04 "clojure.core$partial$fn__4529@5eb8fe04"] user=> (apply (partial add 1 1 ) nil) 2 user=> ((partial add 1 1 )) 2 user=> ((partial add 1 1 1)) ArityException Wrong number of args (3) passed to: user/add clojure.lang.AFn.throwArity (AFn.java:429) user=>
user=> (def add1 (partial + 1)) #'user/add1 user=> (add1) ;=> 1 user=> (add1 2) ;=> 3 user=> (add1 2 3 4) ;=> 10 user=> (= (add1 2 3 4) (+ 1 2 3 4)) ;=> true
(def times (partial *)) (times 1) ; -> 1 (times 1 2 3) ; -> 6 (* 1 2 3) ; -> 6 (def add-hundred (partial + 100)) (add-hundred 1) ; -> 101 (add-hundred 1 2 3) ; -> 106 (+ 100 1 2 3) ; -> 106
;; Check if a character is vowel (def vowel? #(some (partial = %) "aiueo")) (vowel? \e) ;;=> true (vowel? \c) ;;=> nil
;; apply feeds sequence items as variable args to the conj function ;; variable args gets converted to list in the function arg and hence conj ;; adds them as a list (apply #(conj [0 1] %&) [2 3 4 5]) ;;=> [0 1 (2 3 4 5)] ;; Partial offers are mechanism to feed the variable args as is to the conj ;; function effectively like (conj [] 2 3 4 5) (apply (partial conj [0 1]) [2 3 4 5]) ;;=> [0 1 2 3 4 5]
;;practical example (def add-domain (partial #(str % "@clojure.com"))) (add-domain "info") ;;"info@clojure.com"
(defn email-struct [username domain] (str username "@" domain)) (def build-email #(partial email-struct %)) ((build-email "info") "example.com") ;;"info@example.com"
;; partial does not gel well with pure java methods ;; Wrap Java method in Clojure fn (defn letter? [ch] (Character/isLetter ch)) ;; Idiomatic (filter letter? "hello, world!") ;; => (\h \e \l \l \o \w \o \r \l \d) ;; This works (filter (partial letter?) "hello, world!") ;; => (\h \e \l \l \o \w \o \r \l \d) ;; This also works (filter #(Character/isLetter %) "hello, world!") ;; => (\h \e \l \l \o \w \o \r \l \d) ;; This doesn't (filter (partial Character/isLetter) "hello, world!") ;; => Unable to find static field: isLetter in class java.lang.Character
;; Beware that partial "bakes in" the original function and does not look it up ;; again at call time, which can be confusing when mocking. (defn foo [] "hit foo") ;; => #'user/foo (defn mock [] "hit the mock") ;; => #'user/mock (def par (partial foo)) ;; => #'user/par (with-redefs-fn {#'foo mock} #(foo)) ;; => "hit the mock" (with-redefs-fn {#'foo mock} #(par)) ;; => "hit foo"
;; Partial application by calling partial significantly differs from partial ;; application by wrapping a function call in an anonymous function. ;; The code representing the to-be-applied function and to-be-applied-to arguments ;; - with the 'call to partial' approach ;; - is evaluated exactly once, when the call to partial is evaluated. ;; - is not evaluated when a call to the resulting function is evaluated. ;; - with the 'wrapped in an anonymous function' approach ;; - is not evaluated when the anonymous function is evaluated. ;; - is evaluated anew each time a call to the anonymous function is evaluated. ;; If there are side effects involved in obtaining the to-be-applied function or ;; to-be-applied-to arguments (because of with-redefs, this includes referring to a ;; var by providing a symbol), carefully consider which approach to take. (defn fetch-processing-fn! [] (prn "fetching...") (fn [entity] entity)) (defn load-entity! [id] (prn "loading...") :entity) (def top-level-fn-1 (partial (fetch-processing-fn!) (load-entity! 123))) ;; "fetching..." is printed. ;; "loading..." is printed. (top-level-fn-1) ;; Nothing is printed. (top-level-fn-1) ;; Nothing is printed. (def top-level-fn-2 #((fetch-processing-fn!) (load-entity! 123))) ;; Nothing is printed. (top-level-fn-2) ;; "fetching..." is printed. ;; "loading..." is printed. (top-level-fn-2) ;; "fetching..." is printed. ;; "loading..." is printed.
Takes a set of functions and returns a fn that is the composition of those fns. The returned fn t...
Takes a set of functions and returns a fn that is the juxtaposition of those fns. The returned fn...
Applies fn f to the argument list formed by prepending intervening arguments to args.