Interactive Development with Clojure
9:46 PM EDT Friday, July 11 2008
A screencast on interactive development with Clojure.
9:46 PM EDT Friday, July 11 2008
A screencast on interactive development with Clojure.
6:34 PM EDT Wednesday, July 2 2008
I just posted a short screencast on how to get started with Clojure and Aquamacs:
One of the fun features of Clojure, or any Lisp I suppose, is the interactive development workflow. As you can see in the video, you write code by creating expressions that define functions and then you evaluate those functions in the REPL (Read-Eval-Print-Loop). You can redefine a function at any time. You can imagine that if you had a production system running, you could connect to it via a REPL or something like that, evaluate some expressions that redefine functions that contain bugs, and the system would be fixed with no downtime.
Here's the contents of the ~/bin/clj script:
#!/bin/bash
SRC_DIR=/Users/pbarry/src
CLOJURE_JAR=$SRC_DIR/clojure/clojure.jar
JLINE_JAR=$SRC_DIR/jline/jline-0.9.94.jar
if [ -z "$1" ]; then
java -cp $JLINE_JAR:$CLOJURE_JAR jline.ConsoleRunner clojure.lang.Repl
else
java -cp $CLOJURE_JAR clojure.lang.Script $1
fi
3:50 PM EDT Tuesday, March 18 2008
Ruby:
>> 850/550
=> 1
Python:
>>> 850/550
1
JavaScript:
>>> 850/550
1.5454545454545454
Perl:
perl -e 'print 850/550'
1.54545454545455p
Lisp:
[1]> (/ 850 550)
17/11
11:47 AM EST Saturday, December 22 2007
As a result of reading Steve Yegge's latest blog rant, I have discovered a few new interesting things. Steve's rant is very anti-Java for all the right reasons, but falls apart when it gets to the "So here's what I'm going to do about it" part. He's switching to another language, one that runs on the JVM, but not Lisp, Jython, JRuby or Groovy, but for apparently no good reason, JavaScript. Not that JavaScript is a bad language, but I see reason why you would choose that over Lisp, Python or Ruby, and he fails to offer one.
The good thing is that through the comments of this post I learned about a few things, either directly or indirectly. Some of these thing have been around for a long time, but hey, I'm just learning about them.
First, there is a ground swell of support for Scala. I checked out the docs on their site and does look like a very powerful, expressive language. It seems to have many of the features of Lisp without being a Lisp dialect. It is syntactically Java-ish, but unlike Groovy, which really for some reason just seems like much-needed syntactic sugar for Java, Scala feels lieke a completely different language. In other words, and not that this is saying Groovy is a bad thing, but Groovy really isn't conceptually different than Java, where as Scala is, with things like case classes, for example. This is a language I'll have to look into some more.
There is also a mention of a new List-dialect for the JVM called Clojure. Clojure creator Rich Hickey (you need a blog Rich) recently gave a presentation on Clojure at LispNYC and the audio and slides are there. Clojure has a bunch of interesting ideas in it which he explains in the presentation. Clojure has a literal syntax for vectors (a.k.a arrays, lists) and maps (a.k.a Hashtables, Dicts) in addition to the traditional lisp lists. It is not quite a purely functional language, but strongly encourages it, making it the default programming paradigm over object-orientation. I've been wanting to check out Haskell and Erlang to get familiar with the functional programming paradigm, but Clojure might be a good way to get some exposure to that as well.
Another thing I found is Lisplets, which was created by Rich Hickey as well a few years ago. It is a Java Servlet that packages up the entire environment of an HTTP request, request parameters, cookies, session, etc, into an S-expression that is then handed off to a Lisp interpreter that listens on a socket. Lisp then reads the s-expression, does whatever it does, and then returns data to the Servlet which gets sent to the client. Mod_lisp is based on a similar concept. I think it's kind of interesting to think of web development in this manner, with a definitive layer of abstraction between the processing of request into a data structure, and then processing the request based on that data structure.
11:16 PM EST Monday, November 26 2007
Chapter 9 of Practical Common Lisp has us diving deeper into Lisp macros by creating a test framework, which I will of course, try to port to Ruby. The more I continue to work on this, the more I'm convinced this is a great way to learn a new language.
First off, you are forced to digest the examples that you convert, because you have to think about what the code is doing and how you would do it in the language that you know. The bonus payoff is that you now have code in both languages to compare, so you can evaluate the two languages side-by-side. So on with the code.
Right off bat we run into a small problem, which is that you can't have "+" or "*" characters in the name of a method in Ruby. That's ok, we can work around that:
def test_plus
1 + 2 == 3 &&
1 + 2 + 3 == 6 &&
-1 + -3 == -4
end
Which works:
paulbarry@paulbarry: ~/projects/practical_common_ruby $ irb
irb(main):001:0> load 'chap9.rb'
=> true
irb(main):002:0> test_plus
=> true
Next we tackle the version with test case info:
def test_plus
puts "#{eval("1 + 2 == 3") ? 'pass' : 'FAIL'} ... 1 + 2 == 3"
puts "#{eval("1 + 2 + 3 == 6") ? 'pass' : 'FAIL'} ... 1 + 2 + 3 == 6"
puts "#{eval("-1 + -3 == -4") ? 'pass' : 'FAIL'} ... -1 + -3 == -4"
end
Now a little refactoring by adding report_result:
def report_result(result, form)
puts "#{result ? 'pass' : 'FAIL'} ... #{form}"
end
def test_plus
report_result(1 + 2 == 3, "1 + 2 == 3")
report_result(1 + 2 + 3 == 6, "1 + 2 + 3 == 6")
report_result(-1 + -3 == -4, "-1 + -3 == -4")
end
This isn't really very clean, first of all because of the obvious duplication of the actual code and the name, but secondly, we have our code as an argument to the report_result method. This works in lisp, because everything is just an expression, but in Ruby, once this method gets more complicated, this is going to be ugly. So I'm going to refactor report_result to allow for two conditions. The first just takes the code as a string and evals it, using the code as the "name" of the test. Second, the string is the "name" and the block has the code. I think this makes sense, because even in lisp, if the code is some long, multiline expression, you aren't going to want that to be the name of the test, you are going to want to supply a shorter, more descriptive name.
def report_result(test)
if block_given?
result = yield
else
result = eval(test)
end
puts "#{result ? 'pass' : 'FAIL'} ... #{test}"
end
def test_plus
report_result "1 + 2 == 3"
report_result "1 + 2 + 3 == 6"
report_result "adding negative numbers" do
-1 + -3 == -4
end
end
The next refactoring is to define a check method that takes multiple "tests" and prints the results of each one, mainly because the repeated calls to report_result is considered unappealing. I'm not sure there is a particularly cleaner version of this in Ruby, but here's the best I've got:
def report_result(test)
if block_given?
result = yield
else
result = eval(test)
end
puts "#{result ? 'pass' : 'FAIL'} ... #{test}"
end
def check(*tests)
tests.each do |t|
if t.is_a?(Hash)
report_result t.keys.first, &t.values.first
else
report_result t
end
end
end
def test_plus
check(
"1 + 2 == 3",
"1 + 2 + 3 == 6",
"adding negative numbers" => lambda{ -1 + -3 == -4 }
)
end
I found this tutorial on Ruby's Procs and Blocks to be helpful while working on this. In reality, I think most Ruby programmers would stick to the original version of test_plus over this version that uses Hash and Lambdas, but I'll stick with this one because it's closer to the actual code in the example. A couple of small changes give us the ability to track if the test has a failure:
def report_result(test)
if block_given?
result = yield
else
result = eval(test)
end
puts "#{result ? 'pass' : 'FAIL'} ... #{test}"
result
end
module Enumerable
def each?
result = true
each do |i|
result = false unless yield(i)
end
result
end
end
def check(*tests)
tests.each? do |t|
if t.is_a?(Hash)
report_result(t.keys.first, &t.values.first)
else
report_result(t)
end
end
end
I choose to implement the combine_results function from the example as an iterator called each? mixed-in to Enumerable, so that we can call it in the idiomatic Ruby way tests.each?. each? is similar to the all? method that already exists in Enumerable, except that all? short-circuits and stops iterating through over the items once the block evaluates to false. We want to always perform the block on each item in the enumerable, and then return false if any are false. I choose to name it each? rather than combine_results because it's more descriptive, more Rubyish. I'm actually kind of surprised Ruby doesn't have a method like that.
Now this next bit require dynamic variables. This is a new concept for me and I have to say, it is pretty cool. The bad news? Ruby doesn't have dynamic variables :(. The good news? We can fake it. Just download this code and we are ready to go. We add in a line to define the variable:
Dynamic.variable :test_name
Then we add it into our test method. We also have to do a little finagling to get them to still return the right value:
def test_plus
result = false
Dynamic.let :test_name => 'test_plus' do
result = check(
"1 + 2 == 3",
"1 + 2 + 33 == 6",
"adding negative numbers" => lambda{ -1 + -3 == -4 }
)
end
result
end
def test_times
result = false
Dynamic.let :test_name => 'test_times' do
result = check(
"2 * 2 == 4",
"3 * 5 == 15"
)
end
result
end
Lastly we just add the dynamic variable to the print statement in report_result:
def report_result(test)
if block_given?
result = yield
else
result = eval(test)
end
puts "#{result ? 'pass' : 'FAIL'} ... #{Dynamic.test_name}: #{test}"
result
end
So now we want to clean up this redundant test code, but alas, Ruby does not have macros. Here we go again, coming pretty close. Define a method we will use to define tests:
def test(name)
test_name = "test_#{name}"
method = lambda do
result = false
Dynamic.let :test_name => "#{Dynamic.test_name} #{test_name}" do
result = yield
end
result
end
Object.send(:define_method, test_name, method)
end
I'm not even going to try to explain how this code works. This is pretty dense. I'm not sure if it is more or less dense than the Lisp code. Now that we have our Ruby "macro" created, we can define our tests like this:
test "plus" do
check(
"1 + 2 == 3",
"1 + 2 + 3 == 6",
"adding negative numbers" => lambda{ -1 + -3 == -4 }
)
end
test "times" do
check(
"2 * 2 == 4",
"3 * 5 == 15"
)
end
test "arithmetic" do
%w{test_plus test_times}.each? do |t|
send t
end
end
test "math" do
test_arithmetic
end
And voila, we have a feature complete version of the test framework in Ruby:
irb(main):096:0> test_math
pass ... test_math test_arithmetic test_plus: 1 + 2 == 3
pass ... test_math test_arithmetic test_plus: 1 + 2 + 3 == 6
pass ... test_math test_arithmetic test_plus: adding negative numbers
pass ... test_math test_arithmetic test_times: 2 * 2 == 4
pass ... test_math test_arithmetic test_times: 3 * 5 == 15
=> true
irb(main):097:0> test_arithmetic
pass ... test_arithmetic test_plus: 1 + 2 == 3
pass ... test_arithmetic test_plus: 1 + 2 + 3 == 6
pass ... test_arithmetic test_plus: adding negative numbers
pass ... test_arithmetic test_times: 2 * 2 == 4
pass ... test_arithmetic test_times: 3 * 5 == 15
=> true
irb(main):098:0> test_plus
pass ... test_plus: 1 + 2 == 3
pass ... test_plus: 1 + 2 + 3 == 6
pass ... test_plus: adding negative numbers
=> true
So in conclusion, macros are one feature of Lisp that have no direct equivalent in Ruby, but you can define methods that define methods, which is pretty close to what macros do. Given Ruby's metaprogramming features like eval, send, and define_method, etc., Do you really need macros?. The search for the answer continues...