Fun With Vars

  • 1,766 views
Uploaded on

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 …

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.

More in: Technology
  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Be the first to comment
No Downloads

Views

Total Views
1,766
On Slideshare
0
From Embeds
0
Number of Embeds
1

Actions

Shares
Downloads
31
Comments
0
Likes
1

Embeds 0

No embeds

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
    No notes for slide

Transcript

  • 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
  • 4. 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
  • 5. ikouCLOJURE sort of demonstration Tuesday, August 11, 2009
  • 6. 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
  • 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