Takes a set of functions and returns a fn that is the composition of those fns. The returned fn takes a variable number of args, applies the rightmost of fns to the args, the next fn (right-to-left) to the result, etc.
(def negative-quotient (comp - /)) ;; #'user/negative-quotient (negative-quotient 8 3) ;;=> -8/3 (def concat-and-reverse (comp (partial apply str) reverse str)) ;; #'user/concat-and-reverse (concat-and-reverse "hello" "clojuredocs") ;;=> "scoderujolcolleh"
;; make a struct 'goods'. it assumes that every goods has ;; its id number and price. (defstruct goods :id :price) ;; generate data. (def data (map #(struct goods %1 %2) (shuffle (range 0 10)) (shuffle (into (range 100 500 100) (range 100 500 100))))) (defn comp-goods-price "a compare function by :price of the struct 'goods.' the sort order is that the lower price is superior to the higher one and if the price is same, the lower id is superior to the higher one." [el1 el2] (if (or (< (:price el1) (:price el2)) (and (= (:price el1) (:price el2)) (< (:id el1) (:id el2)))) true false)) ;; The shuffle will cause your results to differ. data ;;=> ({:id 1, :price 300} {:id 6, :price 100} ;; {:id 3, :price 100} {:id 4, :price 400} ;; {:id 0, :price 300} {:id 2, :price 200} ;; {:id 5, :price 200} {:id 8, :price 400}) (sort (comp comp-goods-price) data) ;;=> ({:id 3, :price 100} {:id 6, :price 100} ;; {:id 2, :price 200} {:id 5, :price 200} ;; {:id 0, :price 300} {:id 1, :price 300} ;; {:id 4, :price 400} {:id 8, :price 400}) (sort-by :price < data) ; compare this with the above. ;;=> ({:id 6, :price 100} {:id 3, :price 100} ;; {:id 2, :price 200} {:id 5, :price 200} ;; {:id 1, :price 300} {:id 0, :price 300} ;; {:id 4, :price 400} {:id 8, :price 400}) ;; Yet another example of 'comp' by PriorityBlockingQueue. (import [java.util.concurrent PriorityBlockingQueue]) ;; java.util.concurrent.PriorityBlockingQueue (def pqdata (new PriorityBlockingQueue 8 (comp comp-goods-price))) ;; #'user/pqdata (doseq [x data] (.add pqdata x)) ;;=> nil (dotimes [_ 8] (println (.poll pqdata))) ;; {:id 3, :price 100} ;; {:id 6, :price 100} ;; {:id 2, :price 200} ;; {:id 5, :price 200} ;; {:id 0, :price 300} ;; {:id 1, :price 300} ;; {:id 4, :price 400} ;; {:id 8, :price 400} ;;=> nil
; We need an example that composes more than just two functions. ; The following example is an overly complicated reimplementation of 'nth' ; but it does show the composition of an arbitrary number of functions (rest). ( #((apply comp first (repeat %2 rest)) %1) [1 2 3 4 5 6] 3 ) ;;=> 4
; `comp`-ing maps, filters with a little help from our friend `partial` ; the following function filters numbers in a `coll` if it is divisible by 3 ; then on that filtered `coll`, multiplies all by 2 ; a little helper to find if a number is div by 3 ; also comp-ed (def mod3nz? (comp not zero? #(mod % 3))) ; now for that elusive function that muls by 2 after filter those not div by 3 (def mul-2-nd-3 "Takes a seq of numbers, filters those not divisible by 3 and muls them by 2" (comp (partial map #(* % 2)) (partial filter mod3nz?))) (mul-2-nd-3 [16 15 30 43]) ;; => (32 86)
; Split a number into sequence of it's digits ((comp (partial map (comp read-string str)) str) 33) ;;=> (3 3)
;; Keywords are used as functions to access data in maps. (:foo {:foo "bar"}) ;;=> "bar" ;; With a nested data structure, it is common to use ;; several keywords in sequence to navigate the hierarchy. (def my-data {:this {:that {:the-other "val"}}}) ;;=> #'user/my-data (-> my-data :this :that :the-other) ;;=> "val" ;; Since keywords are functions, ;; they can be 'comp'ed just like any other function. (def those (comp :the-other :that :this)) ; Note: reverse order ;;=> #'user/those (those my-data) ;;=> "val" ;; The composed keyword-sequence can be used with other keywords: - (def my-data-2 {:this {:that {:the-other {:a "apple" :b "banana"}}}}) ;;=> #'user/my-data-2 (let [a (-> my-data-2 those :a) b (-> my-data-2 those :b)] (str "These: " a ", " b)) ;;=> "These: apple, banana"
;; ((comp func1 func2) data) mean ... ;; (-> data func2 func1) ;; so, ((comp (partial * 3) inc) 1) ;; means (* 3 (inc 1)) ;; advanced ... ((comp seq re-seq) #"(\w+)=(\S+)" "foo=bar") ;; (["foo=bar" "foo" "bar"]) (seq (re-seq #"(\w+)=(\S+)" "foo=bar")) ;; * "#(\w+)..." and "foo=..." are arguments for #re-seq
;; comp is the transducer equivalent to thrush ;; An example of using the "thread-last" macro to get ;; the sum of the first 10 even squares. (->> (range) (map #(* % %)) (filter even?) (take 10) (reduce +)) ;;=> 1140 ;; Many the seq functions now produce transducers. ;; `reduce` does not but has been replaced with `transduce`. (transduce (comp (map #(* % %)) (filter even?) (take 10)) + 0 (range) ) ;;=> 1140
;;trim will remove the white spaces and return a new string which will be passed ;;to the second function capitalize which will return a new string ((comp clojure.string/capitalize clojure.string/trim) " london ") ;;"London"
(def my-car {:name "audi" :data {:cc 2990 :bhp 350}}) ((comp :bhp :data) my-car) ;;350 ;;which is the equivalent of (:bhp (:data my-car)) ;;350
(require '[reagent.core :as r]) (def float-parsable? (comp not js/isNaN js/parseFloat)) (def find-parsable-or-nil (comp first (partial re-find #"(\-?\d+\.)?\d+([eE][-+]?\d+)?"))) (defn number-input "HTML input element for number only input" [value] [:input {:value @value :type "text" :on-change (comp #(when-let [new-value %] (reset! value new-value)) (fn [new-value] (cond (empty? new-value) "" (float-parsable? new-value) new-value :otherwise (find-parsable-or-nil new-value))) (fn [target] (.-value target)) (fn [event] (.-target event)))}]) (def value (r/atom "")) (defn demo [] [:div ; Displays NaN when value is "", displays a number otherwise. (-> @value js/parseFloat str) [:br] [number-input value]])
; Demonstrating the order of parameters vs. normal function application. (def x {:bar {:foo 42}}) (:foo (:bar x)) ;;=> 42 ((comp :foo :bar) x) ;;=> 42
; Without arguments returns identity function (identical? (comp) identity) ;;=> true ((comp) :arg) ;;=> :arg
Takes a function f and fewer than the normal arguments to f, and returns a fn that takes a variabl...
Takes a set of functions and returns a fn that is the juxtaposition of those fns. The returned fn...
Takes a set of predicates and returns a function f that returns true if all of its composing predi...
comp