Great notes Amy. Thanks very much!
> I thought I'd make an attempt at contributing something to the group
> by taking notes last week. Here's my attempt at capturing some of the
> content of the presentation and discussion. At least the "upcoming
> events" are accurate, as they were easy to verify online!
> - Amy
> ========================================
> Portland Functional Programming Study Group, 2008-04-14
> The meeting started off with some informal chat and reminders of
> upcoming events that may be of interest (URLs added post hoc):
> Innotech at the Convention Center (now past)
> Erlounge, an Erlang gathering in Seattle 04/25 @ 6:30 (Kevin later
> posted details to the list - thanks)
> LinuxFest Northwest, April 26-27: http://linuxfestnorthwest.org/
> BarCamp coming up on May 2,3,4: http://barcamp.org/BarCampPortland
> DrupalCampPDX is on May 10: http://groups.drupal.org/node/9748
> ========================================
> Topic: "A Modest Introduction to Clojure"
> Speaker: Patrick Logan
> Patrick gave us an introduction to Clojure in a live-demo
> fashion. This made for an effective mix of presentation and
> discussion.
> Background from the abstract for this talk:
> Abstract: Clojure is a Lisp dialect that runs on the Java Virtual
> Machine. Designed as a general-purpose language, it strives to
> provide a balance between functional purity and practical
> necessity. It includes sophisticated concurrency support that helps
> it ensure clean, correct, multithreaded designs. This talk will
> introduce the important aspects of Clojure as a language on the JVM
> and as a dialect of Lisp, although no experience with either will
> be needed to follow along. The presentation will be primarily
> code-based with only a few slides. [Language homepage:
> http://clojure.sourceforge.net/]
> Speaker: Patrick Logan started programming in Common Lisp in 1984
> and Scheme soon after. Tinkered with Erlang beginning in 1999, and
> occasionally since then. Programmed professionally in Smalltalk off
> and on since 1986, as well as C++, Java, and more, in electronics
> design and manufacturing, financial systems, insurance, and
> peer-to-peer conference systems. Written less than 500 lines of
> Clojure to date, but the language is luring him in.
> Your notetaker last used Scheme 20+ years ago for a class, and can
> claim only to know Java when she sees it, so may well have
> misconstrued a thing or two along the way. Errors in the notes that
> follow are all mine. -akf
> What makes Clojure a LISP?
> * Uses s-expressions as its syntax
> * macros
> * has readtables like Common LISP
> Some quirks and features of Clojure:
> * no car! "first"
> * "second", "rest", "frest", "rfirst", does not go on indefinitely
> like cdadr etc.
> * Uses square brackets a bit differently than scheme -- denotes a vector.
> * Also for binding variables, e.g. (let [a 1 b 3] (+ a b))
> * can use commas as whitespace...
> * type predicates (vector?, class, seq?)
> * cycle -- lazy list
> * has multimethods
> Mostly functional, moreso even than Scheme. Lists, vectors, hashes are
> all persistent and immutable. To define a mutable variable, you can
> use def. Creates a mutable variable that is thread-local. e.g.,
> (let [a 10 b 5] (def ccc 4) (* a b))
> ccc
> => 4
> (def x 4)
> x
> => 4
> (def box (var x))
> Boxes are mutable (thread-local or shared across threads).
> Some quirks: map syntax, treatment of nil:
> (= (cons 1 ()) (cons 1 nil))
> => true
> (= () nil)
> => false
> ... it's unclear whether this is by design, or a bug.
> Recursion: running on JVM, the language is not as recursive as you
> might like. Uses Java call stack, not tail-recursive.
> (defn fact [n] (if (== n 1) 1 (* n (fact (-n 1 ))))) (fact 3)
> Anonymous function of 3 args:
> (#(* 2 %1 %2 %3) 20 30 40)
> => 48000
> (#(* 2 %2 %3) 20 30 40)
> => 2400
> (Adam Jones interjected that the bootstrapping code for defn is
> interesting to read.)
> Metadata - readtable ^# -- next form is the metadata; it will be
> associated with following form.
> (def vec #^{:a 2 :b 6} [1 2 3])
> (meta vec)
> => {:b 6 :a 2}
> Other special syntax: recur, loop
> (defn fact [n]
> (loop [result 1, n n]
> (if (== n 1)
> result
> (recur (* n result) (-n 1)))))
> recur -> back to loop with new binding. Use must be tail-recursive.
> (defn fact
> ([n] (fact n 1))
> ([n result] (if (== n 1)
> result
> (recur (* n result) (-n 1)))))
> Can freely access classes in Java:
> (import '(java.swing....
> Concurrency: vars are thread-local boxes to store mutable values.
> A ref is like a var, but can be seen across threads:
> (def r (ref 3))
> @r
> => 3
> (ref-set r 5)
> => gives us an exception, no transaction running
> (dosync (ref-set r 5))
> @r
> => 5
> commute -- if you know you are applying a commutative operation
> (transaction order doesn't matter), you can use a commute form, and
> the change will be applied at commit time to the current value. It's
> up to you to use this wisely.
> =============== BREAK ===============
> Adam Jones shared some of his experiences working with Java and
> Clojure on a game implementation.
> * importing classes
> * creating objects
> * method calls (. temp-text (getText))
> Clojure supports implementing interfaces from Java with a proxy
> syntax:
> (proxy [Class and Interfaces] [Superclass constructor args]
> f => (name [params*] body) or
> (name ([params*] body) ([params+] body) ...)
> There are limitations to this; Adam doesn't generally use it and
> writes what he needs in Java instead. You cannot call protected
> methods when you do this, and don't get some exceptions until runtime.
> The Clojure developer is moving quickly. Code is changing frequently
> and mostly not well-documented.
> Appeal of Clojure: Adam was looking for a LISP on the JVM. It's much
> faster than Jython, very small.
> Top-level definitions *are* redefinable. It's more immutable by
> convention.
> Patrick noted that transaction conflicts are only handled at the box
> level. If the box points at a Java data structure, you can change the
> Java data structure and the transactional machinery won't know. So
> it's not really safe to replay transactions when Java data structures
> are involved.
> Trying to move mutable state and things that need speed into Java.
> Any time you eval you get a generic Java object. This can lead to
> doing a lot of casting.
> All the Clojure datatypes implement the Iterable interface, so Java
> code can consume them.
> ========================================