A basic intro and exploration into Clojure's Vars... with some fun had with macros. This presentation was given during the Aug. 2009 meeting of the Bay Area Clojure Meetup (http://www.meetup.com/The-Bay-Area-Clojure-User-Group/). Thanks to Amit Rathore for help putting this together. Also, thanks to Runa.com for hosting the Meetup.
Beginners Guide to TikTok for Search - Rachel Pearson - We are Tilt __ Bright...
Fun With Vars
1. FUN with Vars
Bay Area Clojure Meetup
Aug 6, 2009
Kyle Oba
Runa Employee #8
@mudphone
kyleoba@gmail
Tuesday, August 11, 2009
2. agenda
# => ikouCLOJURE
• demonstration of the early stages of an online api lookup tool
how routing works in WEBBING
• why not start with a macro?
• how it turned out to be a Var problem
READER => EVALUATION => VARS
• in which you should remember THREE things
1. var is a special form
2. this is possible: symbol map Var binding value
3. if a symbol is NOT RESOLVED to a value ON EVALUATION => BOOM!
RECUR
Tuesday, August 11, 2009
3. var = special
sym - Var - value
agenda unresolv’d sym eval boom
# => ikouCLOJURE
• demonstration of the early stages of an online api lookup tool
how routing works in WEBBING
• why not start with a macro?
• how it turned out to be a Var problem
READER => EVALUATION => VARS
• in which you should remember THREE things
1. var is a special form
2. this is possible: symbol map Var binding value
3. if a symbol is NOT RESOLVED to a value ON EVALUATION => BOOM!
RECUR
Tuesday, August 11, 2009
7. ikouCLOJURE : routing
(def routes-map {
"/doc/get" ikou-doc/get-doc
})
FIRST TRY: a macro (why not?)
(defmacro get-doc [thing]
`(with-out-str
(doc ~thing)))
get-doc WORKS at the REPL
but, it doesn’t EVALUATE as part of the routes-map
=> java.lang.Exception: Can't take value of a macro
at clojure.lang.Compiler.analyzeSymbol(Compiler.java:4684)
Tuesday, August 11, 2009
8. ikouCLOJURE : to be absolutely clear about that macro thing
(defmacro m-get-doc [thing]
`(with-out-str
(doc ~thing)))
(defn get-doc-w [x]
(m-get-doc x))
this WON’T EVALUATE
it throws a
java.lang.Exception: Unable to resolve var: x in this context
[Thrown class clojure.lang.Compiler$CompilerException]
Tuesday, August 11, 2009
9. ikouCLOJURE : to be absolutely clear that error
even this WON’T EVALUATE
(defn bogus-doc [x]
(doc x))
it throws a
java.lang.Exception: Unable to resolve var: x in this context
[Thrown class clojure.lang.Compiler$CompilerException]
Tuesday, August 11, 2009
ask folks to remember, we got an ERROR here
10. ikouCLOJURE : unresolvable Var error
why are we getting this error?
java.lang.Exception: Unable to resolve var: x in this context
[Thrown class clojure.lang.Compiler$CompilerException]
Tuesday, August 11, 2009
11. Clojure.org: a small vocabulary lesson
DATA STRUCTURES
READER
COMPILER
EVALUATION
SYMBOL
VAR
Tuesday, August 11, 2009
12. Clojure.org: http://clojure.org/reader
CLOJURE DATA STRUCTURES
“Clojure is a homoiconic language, which is a fancy term describing the fact that
Clojure programs are represented by Clojure data structures.”
“Clojure is defined in terms of the evaluation of data structures and not in terms of
the syntax of character streams/files.”
“That said, most Clojure programs begin life as text files, and it is the task of the
reader to parse the text and produce the data structure the compiler will see. This
is not merely a phase of the compiler. The reader, and the Clojure data
representations, have utility on their own...”
WTF? AWESOME, right?
Tuesday, August 11, 2009
Since itʼs just Clojure data structures, programs can create programs
Clojure programs could begin life as anything that leads to these data structures.
13. ninjas
REALULTIMATEPOWER.NET
Tuesday, August 11, 2009
this is why macros are possible
this is why clojure (and lisps) have parens
14. Clojure.org: http://clojure.org/reader
SRSLY. WHAT DID THAT MEAN?
“One might say the reader has syntax
defined in terms of characters,
and the Clojure language has syntax
defined in terms of symbols, lists, vectors, maps etc.”
text -> READER -> clojure data structures -> COMPILER -> EVALUATION
Tuesday, August 11, 2009
reader reads charaters (as forms)
compiler reads clojure language as clojure data structures, which are the objects returned by the reader
15. Clojure.org: http://clojure.org/Evaluation
EVALUATION
“Evaluation can occur in many contexts:
Interactively, in the REPL
On a sequence of forms read from a stream, via load or load-file
Programmatically, via eval”
text -> READER -> clojure data structures -> COMPILER -> EVALUATION
Tuesday, August 11, 2009
16. var = special
sym - Var - value
Clojure.org: http://clojure.org/Evaluation unresolv’d sym eval boom
EVALUATION
“ Clojure programs are composed of expressions.
Every form not handled specially by a special form
or macro is considered by the compiler to be an expression, which is evaluated to
yield a value...
...a single object is considered by the compiler, evaluated, and its result returned.
If an expression needs to be compiled, it will be. There is no separate compilation
step, nor any need to worry that a function you have defined is being interpreted.
Clojure has no interpreter.”
Tuesday, August 11, 2009
THING TO REMEMBER #1: there are these “special forms”
17. var = special
sym - Var - value
Clojure.org: http://clojure.org/Evaluation unresolv’d sym eval boom
EVALUATION
SYMBOL Resolution
is namespace qualified? -> binding of named global var
is package qualified? -> Java class
else, in order...
1. is special form? -> special form stuff
2. maps to class in current ns? -> Java class
3. binds locally? -> value of local binding
4. maps to Var? -> value of binding of the Var
5. error
If you remember, we were trying to figure out why we had that error...
Tuesday, August 11, 2009
THING #2: if symbol maps to Var, then binding of Var is the evaluated value
THING #3: if symbol is not evaluated to a value, this causes an error
18. back to the error
so, we had that error...
even this WON’T EVALUATE
(defn bogus-doc [x]
(doc x))
it throws a
java.lang.Exception: Unable to resolve var: x in this context
[Thrown class clojure.lang.Compiler$CompilerException]
WHY?
Tuesday, August 11, 2009
19. here’s a hint
“doc” is a macro
which expands like so
user> (macroexpand-1 '(doc map))
(clojure.core/print-doc (var map))
and “print-doc” works like this
user> (print-doc #'map)
-------------------------
clojure.core/map
([f coll] [f c1 c2] [f c1 c2 c3] [f c1 c2 c3 & colls])
Returns a lazy sequence ...
Tuesday, August 11, 2009
20. back to the error
so, our offending fn is expands to
(defn bogus-doc [x]
(print-doc (var x)))
and it throws a
java.lang.Exception: Unable to resolve var: x in this context
[Thrown class clojure.lang.Compiler$CompilerException]
STILL WHY?
Tuesday, August 11, 2009
21. back to the error
now that we know more about symbol resolution and evaluation
let’s take a closer look
java.lang.Exception: Unable to resolve var: x in this context
[Thrown class clojure.lang.Compiler$CompilerException]
Tuesday, August 11, 2009
so maybe the var special form in bogus-doc is causing the problem
22. var = special
sym - Var - value
back to the error unresolv’d sym eval boom
real quick-like...
what does “def” do?
Var without binding
user=> (def x)
#'user/x
user=> x
java.lang.IllegalStateException: Var user/x is unbound.
Var with binding
user=> (def x 1)
#'user/x
user=> x
1
Tuesday, August 11, 2009
what then, is the var special form resolving x to (in bogus-doc)?
23. var = special
sym - Var - value
back to the error unresolv’d sym eval boom
so, it’s the var special form
when “defn bogus-doc” is evaluated
what does (var x) refer to?
(defn bogus-doc [x]
(doc x))
aka
(defn bogus-doc [x]
(print-doc (var x)))
answer: nothing
Tuesday, August 11, 2009
answer: nothing
hence the error
24. var = special
sym - Var - value
an example unresolv’d sym eval boom
you can get my-doc to evaluate properly,
if you declare y first
user> (declare y)
#'user/y
user> (defn my-doc [y]
(doc y))
#'user/my-doc
but, what’s this?
user> (my-doc map)
-------------------------
user/y
nil
nil
nil
Tuesday, August 11, 2009
the doc info for “map” is not correct, it appears to be the doc info for user/y
25. var = special
sym - Var - value
what happened to y? unresolv’d sym eval boom
remember
doc is a macro
user> (macroexpand-1 '(doc filter))
(clojure.core/print-doc (var filter))
var is a special form
so...
• doc expands to (print-doc (var y)) at evaluation
• my-doc's print-doc argument is the Var #'user/y
• the "argument y" ISN’T USED
Tuesday, August 11, 2009
26. var = special
sym - Var - value
another example unresolv’d sym eval boom
another way to say that (var y) isn’t resolving to the fn’s arg
user> (defn verbose-doc [y]
(doc y)
(println y))
#'user/verbose-doc
user> (verbose-doc map)
-------------------------
user/y
nil
nil
#<core$map__4564 clojure.core$map__4564@20cc1fc4>
nil
Tuesday, August 11, 2009
27. RECUR : ikouCLOJURE
so, how do we fix our original problem?
I wanted to get the doc output for an input string.
Tuesday, August 11, 2009
youʼve kicked that dead horse enough
28. RECUR : ikouCLOJURE
this works... and you don’t need a macro
(defn get-doc [str-name]
(with-out-str
(print-doc (resolve (symbol str-name)))))
Tuesday, August 11, 2009
29. var = special
sym - Var - value
RECUR : ikouCLOJURE unresolv’d sym eval boom
why not use "doc" ?
doc is a macro that syntactically replaces
the form with a (var y) special form
when evaluated
(var y) will cause an error if it doesn’t resolve to a value
Tuesday, August 11, 2009
30. finally
an interesting point
• "doc" info is just meta-data
• but where? on the Var, not on the object
• that's why print-doc takes a Var
Tuesday, August 11, 2009
31. finally
an example
metadata sits on the var
user> (meta (var map))
{:ns #<Namespace clojure.core>, :name map, :file "clojure/core.clj", :line
1588, :arglists ([f coll] [f c1 c2] [f c1 c2 c3] [f c1 c2 c3 & colls]), :doc "Returns a
lazy sequence consisting of the result of applying f to then set of first items of
each coll, followed by applying f to the setn of second items in each coll, until
any one of the colls isn exhausted. Any remaining items in other colls are
ignored. Functionn f should accept number-of-colls arguments."}
Tuesday, August 11, 2009
32. var = special
sym - Var - value
finally unresolv’d sym eval boom
if that made sense to you
then this might too
user> (declare y)
user> (defn huh [y]
(doc y)
(binding [map y]
(map "hello")
(meta #'map)))
user> (huh println)
-------------------------
user/y
nil ...
hello
{:ns #<Namespace clojure.core>, :name map, :file "clojure/core.clj", :line
1588, :arglists ([f coll] [f c1 c2] [f c1 c2 c3] [f c1 c2 c3 & colls]), :doc "Returns a lazy
sequence consisting of the result of applying f to then set of first items of each
coll, followed by applying f to the setn ...}
Tuesday, August 11, 2009
33. thank you any questions?
Tuesday, August 11, 2009