OBE
Overcome By Events -- this is my excuse for NOT submitting an entry for the ICFP contest this year. It's Sunday, 0900 EDT as I write this and not a single line of code has been written. On top of that, today is going to be busy. Maybe next year.
ICFP 2009 is off and running!
Well, the ICFP 2009 programming challenge started today. Team Foognostic has signed up (so far includes: me) and has skimmed through the problem description. It's a little premature to judge it, but the task kind of feels like a MMIXed up version of last year's contest.
Unless something awesome happens the physics portion of the challenge will be tackled last, if at all. And I still intend to use Clojure.. I have a little ant based environment to assist.
If anyone is interested in joining team Foognostic, shoot me a mail at tbbs@sbbtabfgvp.arg, unless rot13 ain't your thing. Don't wait though, the contest ends June 29th at 14:00 CDT!
Reduce your way into good Clojure
Standard disclaimer: Clojure is a new hobby.
In my previous post I discussed replacing for loops with the (map) function. That works, until it doesn't.
Another step needed to generate the cosine similarity for two strings is to create a frequency histogram, or how many times each character pair occurs in a string. This is a pretty good fit for a hash map, where the keys are the character pairs, and the values the occurrences.
Here was my initial try. This code meant to do well... but went far, far away from where I wanted. Let's take a detailed look at my failings:
(let [hm (hash-map)]
(map
(fn [key val]
(assoc hm key val))
["a" "b" "a"]
[1 2 3]))
What I wanted: a map like this => {"b" 2, "a" 3}. What I got was three hash maps, each with one key/value pair => ({"a" 1} {"b" 2} {"a" 3}). The intent was to use map to iterate over the sequences, and use assoc to put the key and value into one hash map. And now, for the parade of errors...
- Use the zipmap function to build hashmaps like this:
(zipmap ["a" "b" "a"] [1 2 3])=>{"b" 2, "a" 3} - Variables in the let block cannot be changed...
- ... but I really needed to update the hash map defined in the let block.
Rather than continue to stew uselessly I used Emacs to hop into the #clojure IRC channel. A wonderful person suggested the reduce function; I'd used it once in Ruby where it is best known as inject. I'm going to skimp on my description of reduce a little since that article is so well done.
reduce iterates over a collection like map, but it passes a mutable context to each callback. The return value of reduce is the final value of the context... essentially. I am still coming up to speed on it obviously.
Anyhow, enough yammering. Here is reduce in action:
(reduce
(fn [product key]
(+ product
(* (get l_histo key 0)
(get r_histo key 0))))
0
(keys l_histo)))
Key points:
[l_histo r_histo]-- these are the arguments to the dot-product function.(fndefines an anonymous function.(getgets the value for the specified key from the specified map, returning the final argument when the key is absent.0is the default value forproduct(keysreturns the keys of the specified hash map- Clojure really wins a lot by delegating to Java. This happened for free:
(Math/sqrt 100)=>10.0
So, reduce is a critical step for people coming from imperative programming languages looking to do basic things with collections.
Put that for loop down
Standard disclaimer: Clojure is a new hobby.
I've been spending a lot of time with Clojure recently to prepare for the ICFP 2009 contest. It hasn't been the easiest thing, but the difficulty has come from trying to grasp many new concepts at once. The documentation has been pretty good, and the IRC channel has been pretty worthwhile.
I'm trying to settle on a specific task to accomplish when learning a new language. Something concrete but still a little academic... implementing cosine similarity using character bigrams isn't much code, but it covers enough bases to be useful.
Part of the process involves splitting a string into overlapping character pairs.
Bad old me instinctively thinks "for loop".
Good new me thinks... bad old me probably has it right. But it doesn't feel very Clojure-y. This solution is a little more Clojuriffic, probably still a long shot from idiomatic:
(map
(fn [l r] (str l r))
(seq text)
(rest (seq text))))
Bad old me (BOM) would have iterated over the string using a for loop with an index variable, cycling length - 1 times.
Good new me (GNM) had to take a different approach. I converted the string into two sequences; the first was just the string, but the second was the string minus the first character.
sequence A': [B C D E F]
The (map) function takes a callback and a number of sequences. The callback function gets the nth element from each sequence, and the output from the callback is collected and returned by (map). I don't have to specify a length or repetition count, as (map) stops processing when any of the collections run out of data.
("AB" "BC" "CD" "DE" "EF")
This hasn't taken a lot of time, but more than I like. It has taken A LOT of patience, energy, and focus during that time. But I like finding new ways to solve problems. Now I have a new tool in my nerdbelt, one that pushes the for loop back a little bit.
Clojure for the ICFP 2009 contest?
So the programming contest for the 12th International Conference on Functional Programming is coming up soon -- June 26th - 29th. Last year team Foognostic submitted a Ruby-based solution which made it to the second round. This year we will take another stab at it, this time with Clojure. Anyone else interested?
Last year I installed Trac to help organize things and that was fun, but this year I think BitBucket is the way to go. More features that someone else maintains -- woo!
This year another Foognostic solution will be submitted, barring unexpected events that weekend. For the sake of trying to look cool I will be using Clojure, mostly as an exercise to really explore a Lisp. I'm more familiar with Emacs Lisp, but Clojure is sitting right on top of all those featuriffic Java APIs.
The countdown timer stands at a little more than two weeks. That should be enough time to come up to speed, right? ... or have I just uttered famous last words?
In any event, watch this space for updates!
- The ICFP 2009 contest site.
- The ICFP 2008 task description.


