PRESENTATION
* Patrick Logan: A Modest Introduction to Clojure: A Mostly Functional,
Concurrent Lisp on the JVM
- 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.
REMAINDER
The rest of the meeting will be open for participants to ask questions
and discuss projects, technical challenges, recent developments, etc.
The group's members have a wide range of experiences, so there's never a
shortage of interesting discussions.
-igal
PS: I'm incredibly sorry for posting this so late. I actually posted the
message Thursday night, but made an error that caused it to bounce, then
my spam filter ate the bounces, and thus I didn't realize there was a
problem until now. I'm sorry Patrick. :(
- 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.
========================================
Thanks for taking those excellent notes and posting them. I look forward
to going through these in detail with a REPL and manual to catch up on
what I missed at the meeting. :)
-igal