fun with vars

33
Kyle Oba Runa Employee #8 @mudphone kyleoba@gmail FUN with Vars Bay Area Clojure Meetup Aug 6, 2009 Tuesday, August 11, 2009

Upload: kyle-oba

Post on 20-Jan-2015

1.796 views

Category:

Technology


2 download

DESCRIPTION

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.

TRANSCRIPT

Page 1: Fun With Vars

Kyle ObaRuna Employee #8@mudphonekyleoba@gmail

FUN with Vars

Bay Area Clojure MeetupAug 6, 2009

Tuesday, August 11, 2009

Page 2: Fun With Vars

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:

3. if a symbol is NOT RESOLVED to a value ON EVALUATION => BOOM!

RECUR

symbol Varmap valuebinding

Tuesday, August 11, 2009

Page 3: Fun With Vars

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:

3. if a symbol is NOT RESOLVED to a value ON EVALUATION => BOOM!

RECUR

unresolv’d sym eval boom

var = special

sym - Var - value

symbol Varmap valuebinding

Tuesday, August 11, 2009

Page 4: Fun With Vars

ikouCLOJURE : routing

(def routes-map { ...

"/doc/get" ikou-doc/get-doc "/docs/find" ikou-doc/get-find-doc

"/docs/ns" ikou-doc/docs-for-ns "/names/ns" ikou-doc/names-for-ns

...})

Tuesday, August 11, 2009

Page 5: Fun With Vars

ikouCLOJURE

sort of demonstration

Tuesday, August 11, 2009

Page 6: Fun With Vars

ikouCLOJURE : routing

(def routes-map { ...

"/doc/get" ikou-doc/get-doc "/docs/find" ikou-doc/get-find-doc

"/docs/ns" ikou-doc/docs-for-ns "/names/ns" ikou-doc/names-for-ns

...})

Tuesday, August 11, 2009

Page 7: Fun With Vars

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

Page 8: Fun With Vars

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

Page 9: Fun With Vars

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, 2009ask folks to remember, we got an ERROR here

Page 10: Fun With Vars

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

Page 11: Fun With Vars

Clojure.org: a small vocabulary lesson

DATA STRUCTURES

READER

COMPILER

EVALUATION

SYMBOL

VAR

Tuesday, August 11, 2009

Page 12: Fun With Vars

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, 2009Since itʼs just Clojure data structures, programs can create programsClojure programs could begin life as anything that leads to these data structures.

Page 13: Fun With Vars

ninjas

REALULTIMATEPOWER.NET

Tuesday, August 11, 2009this is why macros are possiblethis is why clojure (and lisps) have parens

Page 14: Fun With Vars

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, 2009reader reads charaters (as forms)compiler reads clojure language as clojure data structures, which are the objects returned by the reader

Page 15: Fun With Vars

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

Page 16: Fun With Vars

Clojure.org: http://clojure.org/Evaluation

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.”

unresolv’d sym eval boom

var = special

sym - Var - value

Tuesday, August 11, 2009THING TO REMEMBER #1: there are these “special forms”

Page 17: Fun With Vars

Clojure.org: http://clojure.org/Evaluation

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 stuff2. maps to class in current ns? -> Java class 3. binds locally? -> value of local binding4. maps to Var? -> value of binding of the Var5. error

If you remember, we were trying to figure out why we had that error...

unresolv’d sym eval boom

var = special

sym - Var - value

Tuesday, August 11, 2009THING #2: if symbol maps to Var, then binding of Var is the evaluated valueTHING #3: if symbol is not evaluated to a value, this causes an error

Page 18: Fun With Vars

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

Page 19: Fun With Vars

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

Page 20: Fun With Vars

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

Page 21: Fun With Vars

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, 2009so maybe the var special form in bogus-doc is causing the problem

Page 22: Fun With Vars

back to the error

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

unresolv’d sym eval boom

var = special

sym - Var - value

Tuesday, August 11, 2009what then, is the var special form resolving x to (in bogus-doc)?

Page 23: Fun With Vars

back to the error

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: nothingunresolv’d sym eval boom

var = special

sym - Var - value

Tuesday, August 11, 2009answer: nothinghence the error

Page 24: Fun With Vars

an example

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

unresolv’d sym eval boom

var = special

sym - Var - value

Tuesday, August 11, 2009the doc info for “map” is not correct, it appears to be the doc info for user/y

Page 25: Fun With Vars

what happened to y?

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

unresolv’d sym eval boom

var = special

sym - Var - value

Tuesday, August 11, 2009

Page 26: Fun With Vars

another example

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

unresolv’d sym eval boom

var = special

sym - Var - value

Tuesday, August 11, 2009

Page 27: Fun With Vars

RECUR : ikouCLOJURE

so, how do we fix our original problem?

I wanted to get the doc output for an input string.

Tuesday, August 11, 2009youʼve kicked that dead horse enough

Page 28: Fun With Vars

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

Page 29: Fun With Vars

RECUR : ikouCLOJURE

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

unresolv’d sym eval boom

var = special

sym - Var - value

Tuesday, August 11, 2009

Page 30: Fun With Vars

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

Page 31: Fun With Vars

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 the\n set of first items of each coll, followed by applying f to the set\n of second items in each coll, until any one of the colls is\n exhausted. Any remaining items in other colls are ignored. Function\n f should accept number-of-colls arguments."}

Tuesday, August 11, 2009

Page 32: Fun With Vars

finally

if that made sense to youthen 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 the\n set of first items of each coll, followed by applying f to the set\n ...}

unresolv’d sym eval boom

var = special

sym - Var - value

Tuesday, August 11, 2009

Page 33: Fun With Vars

thank you any questions?

Tuesday, August 11, 2009