Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why can't I bind + in clojure?

Can anyone explain why I can rebind list but not +?

(binding [list vector]
  (list 1 3))
(binding [list +]
  (list 1 3))
(binding [+ list]
  (+ 1 3))

I'd like to rebind + so I can do partial evaluation.

like image 704
John Lawrence Aspden Avatar asked Feb 28 '10 18:02

John Lawrence Aspden


1 Answers

In Clojure 1.1.0 at least, + with two arguments is inlined for performance. Your binding happens too late. With more arguments it works differently.

Clojure 1.1.0-master-SNAPSHOT
user=> (binding [+ -] (+ 1 2))
3
user=> (binding [+ -] (+ 1 2 3))
-4

One workaround is to make your own namespace and shadow clojure.core/+ with your own function.

user=> (ns foo (:refer-clojure :exclude [+]))
nil
foo=> (defn + [& args] (reduce clojure.core/+ args))
#'foo/+
foo=> (+ 1 2)
3
foo=> (binding [+ -] (+ 1 2))
-1

Note that inlining appears to happen even more aggressively in the current snapshot of Clojure 1.2.0.

Clojure 1.2.0-master-SNAPSHOT
user=> (binding [+ -] (+ 1 2))
3
user=> (binding [+ -] (+ 1 2 3))
6

It may be wisest to use a function name other than +, e.g. add, to avoid confusion.

like image 118
Brian Carper Avatar answered Oct 22 '22 01:10

Brian Carper