views:

146

answers:

2

In my list, addition, the operation + appears as #. How can I make this appear exactly as +? When I eval it, it should also work exactly the same as +.

I guess this would also apply in all kinds of functions in Clojure... Thanks guys.

+1  A: 

An operation is just a piece of code, assigned to a variable. If you want to rebind an operation, you just rebind that variable:

(def - +)
(- 1 2 3)
# => 6

The only problem here, is that the # character is special in Clojure. I'm not sure whether you can use # as a variable name at all, at the very least you will need to quote it when binding it and probably also when calling it:

(def # +)
# => java.lang.Exception: No dispatch macro for: 

Unfortunately, I'm not familiar enough with Clojure to know how to quote it.

Jörg W Mittag
Actually in Clojure 1.1 redefining names which refer to Vars from other namespaces is not so simple. E.g. `(def - +)` normally causes the following at a 1.1 REPL: `java.lang.Exception: Name conflict, can't def - because namespace: user refers to:#'clojure.core/- (NO_SOURCE_FILE:1)`. See my answer for a workaround. This may change in Clojure 1.2.
Michał Marczyk
@Michał Marczyk: Thanks for the correction. I don't actually know any Clojure. I just cracked open *Lord of the REPLs*, typed it in and it worked. No idea what version they are using.
Jörg W Mittag
LotREPLs... 8-O Wow, thanks for mentioning this one! Also, nice to meet you in the Clojure tag, I'm rather a fan of your answers. :-)
Michał Marczyk
@Michał Marczyk: If you like http://LotREPLs.AppSpot.Com/, you might also like http://IDEOne.Com/. Here's a nice comprehensive list of browser-BREPLs: http://Joel.Franusic.Com/Online-REPs-and-REPLs/
Jörg W Mittag
These are great links, thanks!
Michał Marczyk
+5  A: 

The # character is simply not a valid character in symbol names in Clojure (see this page for a list of valid characters) and while it might work sometimes (as it often will), it is not a good practice to use it. Also, it will definitely not work at the beginning of a symbol (actually a literal, you could still do (symbol "#"), though there's probably no point in that). As the Clojure reader currently stands, there's nothing to be done about it (except possibly hacking the reader open to have it treat # (that's '#' followed by a space) as the symbol # -- or simply + -- though that's something you really shouldn't do, so I almost feel guilty for providing a link to instructions on how to do it).

Should you want to alias a name to some other name which is legal in Clojure, you may find it convenient to use the clojure.contrib.def/defalias macro instead of plain def; this has the added benefit of setting metadata for you (and should handle macros, though it appears to have a bug which prevents that at this time, at least in 1.2 HEAD).


And in case you'd like to redefine some built-in names when creating your aliases... (If you don't, the rest of this may not be relevant to you.)

Firstly, if you work with Clojure 1.1 or earlier and you want to provide your own binding for a name from clojure.core, you'll need to use :refer-clojure when defining your namespace. E.g. if you want to provide your own +:

(ns foo.bar
  (:refer-clojure :exclude [+]))

;; you can now define your own +
(defn + [x y]
  (if (zero? y)
    x
    (recur (inc x) (dec y))))

;; examples
(+ 3 5)
; => 8
(+ 3 -1)
; => infinite loop
(clojure.core/+ 3 -1)
; => 2

The need for this results from Clojure 1.1 prohibiting rebinding of names which refer to Vars in other namespaces; ns-unmap provides a way around it appropriate for REPL use, whereas (:refer-clojure :exclude ...), (:use :exclude ...) and (:use :only ...) provide the means systematically to prevent unwanted names from being imported from other namespaces in the first place.

In current 1.2 snapshots there's a "last-var-in wins" policy, so you could do without the :refer-clojure; it still generates a compiler warning, though, and it's better style to use :refer-clojure, plus there's no guarantee that this policy will survive in the actual 1.2 release.

Michał Marczyk