~technomancy/fennel

eb8124f8f9292d696b023584f1816917eeee6ec6 — Mike Richards 2 months ago d8a3192
Evaluate args to partial only once.

Simple literal values (strings, numbers, booleans, and nil) can be
inlined into the function expansion. Everything else (e.g. tables,
symbols, function calls) is bound once in a let form.
2 files changed, 21 insertions(+), 4 deletions(-)

M src/fennel/macros.fnl
M test/core.fnl
M src/fennel/macros.fnl => src/fennel/macros.fnl +17 -4
@@ 180,10 180,23 @@ returns
(fn partial* [f ...]
  "Returns a function with all arguments partially applied to f."
  (assert f "expected a function to partially apply")
  (let [body (list f ...)]
    (table.insert body _VARARG)
    `(fn [,_VARARG]
       ,body)))
  (let [bindings []
        args []]
    (each [_ arg (ipairs [...])]
      (if (or (= :number (type arg))
              (= :string (type arg))
              (= :boolean (type arg))
              (= `nil arg))
        (table.insert args arg)
        (let [name (gensym)]
          (table.insert bindings name)
          (table.insert bindings arg)
          (table.insert args name))))
    (let [body (list f (unpack args))]
      (table.insert body _VARARG)
      `(let ,bindings
         (fn [,_VARARG]
           ,body)))))

(fn pick-args* [n f]
  "Creates a function of arity n that applies its arguments to f.

M test/core.fnl => test/core.fnl +4 -0
@@ 106,6 106,10 @@
               "(let [add (fn [x y z] (+ x y z)) f2 (partial add 1 2)] (f2 6))" 9
               "(let [add (fn [x y] (+ x y)) add2 (partial add)] (add2 99 2))" 101
               "(let [add (fn [x y] (+ x y)) inc (partial add 1)] (inc 99))" 100
               ;; partial evaluates args only once
               "(let [t {:x 1} f (partial + t.x)] [(f 1) (do (set t.x 2) (f 1))])" [2 2]
               "(let [f (partial + (math.random 10))] (= (f 1) (f 1) (f 1)))" true
               "(let [f (partial #(doto $1 (table.insert $2)) [])] (f 1) (f 2) (f 3))" [1 2 3]

               ;; many args
               "((fn f [a sin cos radC cx cy x y limit dis] sin) 8 529)" 529