annotate src/sunil/curry.clj @ 1:c642c73b28e8 tip

added readme
author Robert McIntyre <rlm@mit.edu>
date Tue, 18 Oct 2011 00:49:28 -0700
parents 7cef0e03f29e
children
rev   line source
rlm@0 1 (ns sunil.curry)
rlm@0 2
rlm@0 3 (defmacro def-curry-fn [name args & body]
rlm@0 4 {:pre [(not-any? #{'&} args)]}
rlm@0 5 (if (empty? args)
rlm@0 6 `(defn ~name ~args ~@body)
rlm@0 7 (let [rec-funcs (reduce (fn [l v]
rlm@0 8 `(letfn [(helper#
rlm@0 9 ([] helper#)
rlm@0 10 ([x#] (let [~v x#] ~l))
rlm@0 11 ([x# & rest#] (let [~v x#]
rlm@0 12 (apply (helper# x#) rest#))))]
rlm@0 13 helper#))
rlm@0 14 `(do ~@body) (reverse args))]
rlm@0 15 `(defn ~name [& args#]
rlm@0 16 (let [helper# ~rec-funcs]
rlm@0 17 (apply helper# args#))))))
rlm@0 18
rlm@0 19
rlm@0 20 (defn partial+
rlm@0 21 "Takes a function f and fewer than the normal arguments to f, and
rlm@0 22 returns a fn that takes a variable number of additional args. When
rlm@0 23 called, the returned function calls f with args + additional args.
rlm@0 24 differs from the core version in that it works on just one argument."
rlm@0 25 {:added "1.0"}
rlm@0 26 ([f] f)
rlm@0 27 ([f arg1]
rlm@0 28 (fn [& args] (apply f arg1 args)))
rlm@0 29 ([f arg1 arg2]
rlm@0 30 (fn [& args] (apply f arg1 arg2 args)))
rlm@0 31 ([f arg1 arg2 arg3]
rlm@0 32 (fn [& args] (apply f arg1 arg2 arg3 args)))
rlm@0 33 ([f arg1 arg2 arg3 & more]
rlm@0 34 (fn [& args] (apply f arg1 arg2 arg3 (concat more args)))))
rlm@0 35
rlm@0 36
rlm@0 37 (defmacro decorate
rlm@0 38 "given an unqualified symbol, redefines the associated var to exist in the current
rlm@0 39 namespace and be decorated with the array of decorators.
rlm@0 40 Example:
rlm@0 41 (decorate + memoize)"
rlm@0 42 [sym & decorations]
rlm@0 43 (let [decorations (vec decorations)
rlm@0 44 str-decorations (apply str (interleave decorations " "))]
rlm@0 45 `(let [target-var# (resolve (quote ~sym))
rlm@0 46 old-meta# (meta target-var#)
rlm@0 47 value-of-sym# (var-get target-var#)
rlm@0 48
rlm@0 49 new-meta# (update-in old-meta# [:doc]
rlm@0 50 #(str "*Decorated with: [ "
rlm@0 51 ~str-decorations "]*" \newline
rlm@0 52 %))]
rlm@0 53 (rlm.rlm-commands/undef ~sym)
rlm@0 54 (intern
rlm@0 55 *ns*
rlm@0 56 (with-meta (quote ~sym) new-meta#)
rlm@0 57 ((reduce comp identity (reverse ~decorations)) value-of-sym#)))))
rlm@0 58
rlm@0 59
rlm@0 60 (defmacro defn-decorated
rlm@0 61 "like defn except it accepts an additional vector of
rlm@0 62 decorator functions which will be applied to the base definition.
rlm@0 63 the decorators are applied in left-to-right order."
rlm@0 64 {:author "Robert McIntyre"
rlm@0 65 :arglists '[[name [modifers*] doc-string? attr-map? [params*] body]
rlm@0 66 [name [modifers*] doc-string? attr-map? ([params*] body) + attr-map?]]}
rlm@0 67 [fn-name decorators & defn-stuff]
rlm@0 68 `(do
rlm@0 69 (defn ~fn-name ~@defn-stuff)
rlm@0 70 (alter-var-root (var ~fn-name) (reduce comp identity (reverse ~decorators)))
rlm@0 71 (var ~fn-name)))
rlm@0 72
rlm@0 73
rlm@0 74 (defn curry+
rlm@0 75 "another way to do it, curry+, thanks to duncant"
rlm@0 76 ([num-args f eval-list]
rlm@0 77 (if (= num-args (count eval-list))
rlm@0 78 (apply f eval-list)
rlm@0 79 (fn [& args]
rlm@0 80 (curry+ num-args f (concat eval-list args)))))
rlm@0 81 ([num-args f]
rlm@0 82 (curry+ num-args f '())))
rlm@0 83
rlm@0 84 (defn curry**
rlm@0 85 "curry classic. rlm. consumes stack like a mother"
rlm@0 86 [num-args f]
rlm@0 87 (fn [& args]
rlm@0 88 (let [num-inputs (count args)]
rlm@0 89 (if (= num-inputs num-args)
rlm@0 90 (apply f args)
rlm@0 91 (curry** (- num-args num-inputs)
rlm@0 92 (fn [& more] (apply f (concat args more))))))))
rlm@0 93
rlm@0 94 (defn curry++
rlm@0 95 "takes a function with a fixed number of args and modifies
rlm@0 96 it to that it will be automaticaly curried when called with
rlm@0 97 less args"
rlm@0 98 ([num-args f & eval-list]
rlm@0 99 (if (= num-args (count eval-list))
rlm@0 100 (apply f eval-list)
rlm@0 101 (fn [& args]
rlm@0 102 (apply curry++ num-args f (concat eval-list args))))))
rlm@0 103
rlm@0 104
rlm@0 105
rlm@0 106
rlm@0 107 (def curry* (curry++ 2 curry++))
rlm@0 108
rlm@0 109 (defn-decorated
rlm@0 110 curry
rlm@0 111 [(curry* 2)]
rlm@0 112 "higher order function that enables automatic curying as in haskel, scheme"
rlm@0 113 {:author "Robert McIntyre"}
rlm@0 114 [number-of-args f]
rlm@0 115 (curry++ number-of-args f))
rlm@0 116
rlm@0 117
rlm@0 118
rlm@0 119 ;;; Example of Use
rlm@0 120
rlm@0 121 (defn-decorated
rlm@0 122 demo
rlm@0 123 [memoize (curry 3)]
rlm@0 124 "I like the vector of unitarty higher order transforms ---
rlm@0 125 sort of like a list of modifiers on a magic(tm) card.
rlm@0 126 This function has flying, resistance to black, etc :)"
rlm@0 127 [a b c]
rlm@0 128 (println "side effect")
rlm@0 129 (+ a b c))
rlm@0 130
rlm@0 131
rlm@0 132 ;; (((((demo1)) 1) 2) 3)
rlm@0 133 ;; 6
rlm@0 134