A rather ambitious title but apropos of what I’ve been playing around with this morning. At this month’s Dallas Hack Club, several of us got together and essentially toyed around with problem #1 on Project Euler, learning new things as we went. I ripped through it in Python pretty quickly mostly because I had done it before but partially because Python makes things so easy. After that, I started trying to do it in Clojure, a language I’m interested in but can’t seem to find the time to truly concentrate on.
My initial solution in Clojure was both ugly and uncompilable making it reasonably useless. I’ve been struggling with getting my head truly around functional programming and I finally figured that the solution to that was to do more of it. This summer, in another fit of ADHD and boredom, I bought the electronic version of Chris Smith’s Programming F#. Like most of my projects, little came of it until last night when I decided to work really hard on it for 30 minutes. I figured out Euler’s problem 1 in about 20 minutes and that made me think I should be able to handle Clojure as well.
It took a lot longer than 30 minutes but I finally figured it out in a way that didn’t require 85 lines of Clojure. I think the functional style is starting to sink in. Doing both F# and Clojure seems to hammer home the concepts because I can develop a solution in F# in a medium I’m comfortable in (.Net and Visual Studio) and then move to Clojure with a little more background to build from. The solutions are provided below as a reference.
def main(): sum = 0 for x in range(1, 1000): if x%3==0 or x%5==0: sum+= x print sum
This was the original solution in Python. After doing the F# and Clojure work, I came up with something shorter if slightly more obtuse:
reduce(lambda x, y: x+y, filter(lambda x: x%3==0 or x%5==0, range(1, 1000)))
Those two lambdas are not good for long term maintenance and aren’t that readable. A list comprehension in place of the filter would be a good deal clearer.
reduce(lambda x, y: x+y, [num for num in range(1, 1000) if x%3==0 or x%5==0])
So we’re down from 5 lines to 1 while retaining a good deal of readability. Maybe there really is something to this “Functional programming makes you a better programmer” stuff.
In unimproved F# (I’m open to suggestions):
let result (acc : int) x = if x % 3 = 0 || x % 5 = 0 then acc + x else acc List.reduce result [0..999];;
And finally, in what I think is decent Clojure:
(defn isdiv [x] (or (= (rem x 3) 0) (= (rem x 5) 0))) (reduce + (filter isdiv (range 1 1000)))
Sorry for not having syntax highlighting for the Clojure or F# code, they would both be a great deal more readable. However, it’s interesting to see in Clojure how all functions are first class, e.g. I can pass the + operator to the reduce function instead of having to define a lambda as I did in Python.
I have a feeling the Clojure code could be more succinct but for a first working cut, I’m pretty pleased with it. It’s clean and easy to read, even for someone like me with little exposure to the prefix notation and all the parens.
Overall, I feel less dumb than I did when I woke up this morning. I’m guessing the beer I drink at tonight’s Halloween party will fix that though.