5 ms·
Because keywords are functions which are implemented such that: (:keyword m) calls in turn (get m :keyword) That's just a basic feature of the langu
by prospero 14y ago
Because keywords are functions which are implemented such that:
(:keyword m)
calls in turn
(get m :keyword)
That's just a basic feature of the language. No macros involved.
- dschiptsov 14y agoSo, reader knows about keywords and does this implicit syntactic transformation? It seems to me that a function must be defined somewhere before one could call it.)
- bloat 14y agoNo, there is no syntactic transformation. The keyword is a function i.e. (in Java terms) it implements the IFn interface. The effect of that function is the same as calling the get function on a map using the keyword as the argument.
- dschiptsov 14y agoIn Lisp terms, however, a keyword is a self-evaluating symbol, a constant. If it is a function, where it is defined and when? That's why I'm arguing that this form is confusing, and that transformation is more correct notion, at least if people are insisting to call it Lisp.)
- bloat 14y agoIt does evaluate to itself and it is constant. It is also a function though, and can be used in the function position of a function application just like any other function. Keywords and all their functionality are defined as a primitive in Clojure, i.e. in the Java source code for the language. It's typically one of the first things people learn when they pick up Clojure, and is used as an idiomatic way to access maps whose keys are keywords. I would argue that is is not confusing and that it is totally consistent - all you were missing is one fact: keywords are functions.
- dschiptsov 14y agoFrom the Lips's perspective it is a contradiction. Something is either a function or a constant. The logic is that this object could be called as a function and at the same time always evaluated to itself? That means whenever you call it you always getting it back - this is behavior of a constant. But if you could call it with an argument, you will get back some value, different from whatever it is? As long as maps are immutable, it will behave as a function - return the same value for the same argument. OK, but, please, don't tell me that this isn't confusing.)
- chc 14y ago> That means whenever you call it you always getting it back - this is behavior of a constant. No! You're confusing functions-as-callable-things and functions-as-values. The phrase "a constant" does not generally imply anything about a thing's behavior when called. It just means something whose value will never change. A self-evaluating constant is a constant that circularly evaluates to itself — nothing else can have that value without referring to the constant. But neither of these things have to do with calling anything; they're just about taking values. A constant can certainly refer to a function that returns something other than that constant. For example, in Ruby: `Example = lambda { 1 }`. If you just evaluate "Example", you will get a Proc value, but if you call Example, you will get the Fixnum 1. In most languages that have them, you cannot call a self-evaluating constant. It won't return itself — it's just not a callable thing. In Clojure, keywords are self-evaluating constants that have the behavior of looking themselves up as a key in the argument when called. They serve the purpose of self-evaluating constants exactly the same as in other languages, but they also have the handy property of doing map lookups.
- baar 14y agoGood explanation! Evaluation is what happens when you give something as a parameter. Calling is what happens when you do "(f ...)". Just a little concrete example: Welcome to Racket v5.3.1. > 'foo 'foo > ('foo) application: not a procedure; expected a procedure that can be applied to arguments given: 'foo arguments...: [none] context...: /usr/lib/racket/collects/racket/private/misc.rkt:87:7
- nathell 14y ago> If it is a function, where it is defined and when? Call it "callable" if you prefer. Much the same way as in C++ objects that define operator() are callable; only cleaner.
- mjw 14y agoThe keyword syntax is transformed into a keyword instance by the reader, and keyword instances implement IFn as objects on the JVM, hence can be used as functions under clojure's evaluation rules. As I understand it, the roles which things like lists and functions play in a traditional lisp are replaced in Clojure by abstract datatypes corresponding to Java interfaces. Which on one hand is kinda neat because the core lisp datatypes aren't tied to specific concrete implementations and other datatypes (including user-defined ones) can participate in the same abstractions. On the other hand it means the semantics become quite tied up in underlying JVM-related details and don't seem as clean/elegant as (say) Scheme.
- dschiptsov 14y agoI more than agree with your last paragraph.
- fogus 14y agoOn the other hand it means the semantics become quite tied up in underlying JVM-related details and don't seem as clean/elegant as (say) Scheme. That's not very true. Instead, Clojure is defined in terms of specific abstractions. Whether those take the form of interfaces or protocols is irrelevant because it's the abstractions that count. If it were tied strictly to JVM-related details then ClojureScript would have been much harder to implement than it was. The elegance of Scheme is subjective.
- mjw 14y agoYou have to use the java interop facilities if you want your own types to implement these abstractions though right? I recall some debate about changing this so you can implement them using the native abstraction facilities in clojure (protocols), at which point I'd probably withdraw my point. But yeah elegance is subjective. I use Clojure and broadly like it, JVM interop is really useful, but the lack of a crisp separation between clojure semantics and JVM semantics does still irk the purist in me a bit. I guess I'd see Clojure and ClojureScript not as one language on two host platforms, but as one JVM language and another similar but not really source-compatible language on another platform which is influenced by it. Part of the philosophy seems to be to make pragmatic decisions which blur the boundary with the host platform, rather than try to abstract over the differences in APIs and runtime semantics.
- prospero 14y agohttps://github.com/clojure/clojure/blob/master/src/jvm/clojure/lang/Keyword.java#L132 https://github.com/clojure/clojure/blob/master/src/jvm/cloju...
- jimbokun 14y agoThe code itself is more concise and comprehensible than the prose explanations here. :)