So I decided to take a look at some of the old homework problems and see how they would size up in clojure vs. ML in simplicity and usability, all the while considering things such as typing, polymorphism, etc.
Ex 1: Ch 9 – square sum problem. Take a list, square the members, and sum them all up as one
ML: fun sqsum l = foldr (op +) 0 (map (fn x => x * x) l)
Clojure: (defn sqsum [l] (reduce + (map #(* % %) l))
Clojure v 2: (defn sqsum [l] (reduce + (map (fn [x] (* x x)) l))
Clojure v 3: (defn sqsum [l] (apply + (map #(* % %) l))
This example shows remarkable similarities between these two functional languages. foldr and reduce operate in the same order; but there is no clojure-equivalent to foldl. Both utilize anonymous functions to complete the problem at hand, but in Clojure, we have two ways to write these functions. The standard method is listed above as Clojure v 2, and as we can see, this is very similar to the ML version. The # before a parenthetical block denotes an anonymous function to be written in short-hand form. The % character used in an anonymous function maps the % to a list member in order to apply the function. So # (* % %) multiplies each list member by itself. This shorthand, I feel, saves time and effort in programming while still preserving readability (so long as someone has learned a bit about the language). I also feel the reduce in Clojure is slightly more convenient than that of foldr/l in ML, as ML requires an additional parameter (a starting value) where Clojure’s reduce does not. It could potentially be more efficient as well; if no values are being bound to a var x for each part of the map, we may be saving some computing space. There are so many ways to do the problem in clojure!
Ex 2: pattern matching
ML: fun third (one::two::three::list) = three;
Clojure: (defn third [[_ _ x]] = x)
Clojure has a way of pattern matching called destructuring, which allows one to take a list and break it down into component parts. This makes it pretty easy to find the third element in a list (underscore is a wildcard char, so [_ _ x] makes x the third element) Clojure is more resilient in its returns in this situation – if the input list is less than 3 members in length, then it will return nil, whereas the ML function will return an error due to the fact that the definition above is non-exhaustive (no case for 0 to 2 elements). Clojure seems to handle the exhaustion process for the programmer.
I’ll add more examples later, haven’t had time to find good problems to work on.
Add a comment