Life1D - Putting my Clojure hat back on

2009-11-24 23:35:19

In my last post I disassembled Mr. Harms Cellular Automaton bit by bit, showing how the use of notation as a tool for thought enabled him to write that program mentally while grocery shopping. Today I'll revisit the same problem using Clojure, demonstrating the J-effect.




Preface

The cellular automaton which works in one-dimension has a very simple behavior, despite the many rules. If you haven't yet read the explanation of the J program, now might be a good time to do so: link. (skip down to The Example)

After posting last night I wanted to review some of the other solutions to the simple cellular automaton, not looking for the code but the thoughts behind the code and I was a little surprised at one of the contributions. A much older dialect of Lisp than Clojure is Common Lisp and the solution developed therein looks like so:

(defun value (x)
  (assert (> (length x) 1))
  (coerce x 'simple-bit-vector'))

(defun count-neighbors-and-self (value i)
  (flet ((ref (i)
           (if (array-in-bounds-p value i)
               (bit value i)
               0)))
    (declare (inline ref))
    (+ (ref (1- i))
       (ref i)
       (ref (1+ i)))))

(defun next-cycle (value)
  (let ((new-value (make-array (length value) :element-type 'bit')))
    (loop for i below (length value)
          do (setf (bit new-value i)
                   (if (= 2 (count-neighbors-and-self value i))
                       1
                       0)))
    new-value))

(defun print-world (value &optional (stream *standard-output*))
  (loop for i below (length value)
        do (princ (if (zerop (bit value i)) #\. #\#)
                  stream))
  (terpri stream))

(loop for previous-value = nil then value
          for value = #*01110110101010100100 then (next-cycle value)
          until (equalp value previous-value)
           do (print-world value))

What sticks out when you read that? For me 2 very important things

  1. Its very different from how I would solve it in Clojure
  2. Its very different from how Mr. Harms solved it in J
  3. You have to read it very slowly to deduce what the developer was thinking

And so to me this posed an even more interesting question:

Has J already shaped the way I think?


The J-Effect?

When you look at Mr. Harms solution, what do you see?

    life1d=: '_#'{~ (3(2=+/\) 0,],0:)^:a:


I see this:

jplanation


Being a Clojurian it's only natural that I fall back on my strongest frame of reference, which is Clojure. When I read Mr. Harms program with the references being Clojure-functions its only natural that my program will mimic Mr. Harms quite strongly and that's not a bad thing. You see J more clearly than any language I've come across expresses exactly what the problem is, and then lets the compiler worry about how to solve it.

Here's one way to solve the same problem in Clojure:

(defn life1d [s]
     (let [life (iterate (fn [i]
                               (map #(if (= 2 (reduce + %)) 1 0)
                                    (partition 3 1 (concat [0] i [0])))) s)
           render (partial map {0 \_ 1 \#})]
       (loop [iteration life]
         (println (apply str (render (first iteration))))
         (when (not= (first iteration) (second iteration))
           (recur (next iteration))))))


I wrote it so I'm biased, but what do you think? Is the intention and algorithm coming across more clearly despite being substantially shorter with less sub-routines than the CL version?


Final thoughts

All my blogposts having been leading up the The Manifesto and Mind Games. Together they represent the groundwork for my programming experience. I have come to treasure the way Functional Programming focuses on the what and not the how, when solving problems. I feel J is already helping me improve on the ability to clearly express the problem at hand, since J has almost no notion of how. On the J Mailing List the question was recently asked: How clear is this to you?

3435 = +/ ^~ 3 4 3 5

The first few answers all lined up with Dan Brons experience "Perfectly clear, its asking if a number is equal to the sum of its digits raised to their own power". When you wield J as a tool for describing problems, you gain the ability to be even more clear than what is possible with the english language and the english language is abundantly more clear than an imperative program. Your mileage may vary, but for me its starting to look like it will be a valuable tool to first outline a problem description in J then converting to Clojure for use in production.

If I've caught your attention, please read the rest of Mr. Brons reply: here

fogus
2009-11-25 03:16:58
I'm enjoying your posts, I can't say that J looks much more to me than line-noise, but your advocacy is compelling enough for me to look deeper.  Keep up the good work.  

-m
fogus
2009-11-25 03:27:11
You motivated me to play around with describing the same mathematical property in Clojure:

(reduce + (map #(Math/pow % %) [3 4 3 5]))

(->> [3 4 3 5] (map #(Math/pow % %)) (reduce +))

:)

-m
Lau
2009-11-25 09:21:49
Hey Fogus,

Regarding line-noise then you're describing what I felt when I first saw Mr. Harms comment in 'The Manifesto'. I was planning to let him know, that only the writer of such hideous looking code could read it, but then I tripped over his blog. When he explained how he mentally wrote a program, which probably would take a C programmer 2 hours to do, and a Clojurian 15 minutes, then that fascinated me enough to pick it up, and surprise surprise: The line-noise mutates into code before your very eyes :)

I hope you have some fun with it! You might actually enjoy the solution to Project Euler #3  ***SPOILER***

<strong>Problem</strong>: Find largest prime-factor of the number 600851475143
<strong>Solution</strong>: {:q: 600851475143x

Runs in about 0.000161 seconds :)
Joel Mueller
2009-11-30 03:32:00
Sorry for the off-topic post, but when I was reading this article and the comments that follow, it occurred to me that your perspective on the revTalk language might be rather interesting. And entertaining. In case you're interested, just wanted to bring it to your attention.

http://community.zdnet.co.uk/blog/0,1000000567,10014516o-2000458459b,00.htm
Lau
2009-11-30 10:39:27
Hey Joel, 

Well maybe thats a topic for a future language comparison. I think the blog post you link attempts at a dramatic punch line with superficial background. I reviewed the C# vs Rev and PHP vs Rev and I didn't cannot determine if the program dumbs down the programmer, to me it just looks like high-level abstractions fused into a syntax which is clever for marketing. They had an example like

"get the last item of line 2 of URL www.ichart.com"

Which I would <strong>love to pitch in a sales discussion</strong>, but which is actually bloated, ie "the", "of"x2 etc.

(last (second (get-html "www.icart.com"))) 

is not only shorter, but also works with all of Clojure normal sequences, be it lines, strings, arrays, maps, you name it. If I had to take a <em>wild guess</em>, the other of that blogpost is more opposed to highlevel languages than anything else.

/Lau
Joel Mueller
2009-11-30 19:12:07
I guess what I found interesting is that the advocates for revTalk in the comments section make a lot of claims for their favorite language that sound like some of the things you like about Clojure. But then they turn around and say that non-programmers can use it, and I get suspicious. They claim it's good for enterprise apps, but in my brief and half-hearted search I couldn't find a single example of how a non-programmer might handle multi-threading using their language. I suspect it's one of those things that doesn't require much code until you run out of things that they've pre-built functions for, and then the amount of code you have to write explodes - sort of like ColdFusion. But who knows, maybe it's an elegant general-purpose language that only -seems- scammy.
Lau
2009-11-30 19:43:46
@Joel: I think your concern regarding code explosion is valid. There have been some example in Clojure where I've requested that certain bits were automated, because I didn't feel like I should have to deal with, but Rich with his experience foresaw situations where the compiler couldn't make the decision. So I couldn't imagine that they can enable 'non developers' to develop anything with a moderate degree of complexity. But besides that, there a lot of software floating around which doesn't handle complexity either, so who knows, maybe it'll be the next big thing :)
Daniel Sobral
2009-12-03 15:53:05
What tool did you use to make the image of what you see when you look at Mr Harms' code?
Lau
2009-12-03 19:04:51
@Daniel: Inkscape