I got done with chapter 4 of Programming Clojure. This chapter was about functional programming.
Interestingly, they did not spend much time in this chapter on the concept of higher-order functions. They did use them, but it was not a major part of their definition of “functional programming”. They talked more about purity, referential transparency, immutability, persistent data structures, recursion, and laziness and eagerness (for both collections/sequences and transformations).
I have noticed that when Lisp/Scheme programmers talk about “functional programming”, they tend to talk about functions: higher-order, purity, immutability, laziness. When Haskell or Scala programmers talk about “functional programming”, they talk about types as much as they talk about functions.
The section on lazy sequences blew my mind. They worked with Fibonacci numbers, and I made a lazy sequence of factorials. It is amazing that you can calculate some very large numbers very quickly without blowing the stack.
In case you were wondering, here is 200 factorial (split across a few lines so there is no horizontal scroll):
788657867364790503552363213932185062295135977687173263294742533 244359449963403342920304284011984623904177212138919638830257642 790242637105061926624952829931113462857270763317237396988943922 445621451664240254033291864131227428294853277524242407573903240 321257405579568660226031904170324062351700858796178922222789623 703897374720000000000000000000000000000000000000000000000000N
That’s 7.88657 times 10 to the 374th. My answer matches what is on Calculator Soup.
Here is my sequence:
(defn lazy-seq-fact ( (concat [1N 1N 2N] (lazy-seq-fact 3N 2N))) ([a b] (let [n (* a b)] (lazy-seq (cons n (lazy-seq-fact (inc a) n)))))) (nth (lazy-seq-fact) 200)
I am not quite sure I understand transducers or eduction as well as I would like. (I think they may be changing the meanings of the words “eduction” and “transducer” slightly.) I think one of the ideas behind transducers is that a transducer can be more efficient and do things in fewer steps. A threading macro with multiple functions will make a sequence or collection at each step. A transducer does not. They had a couple of examples that they converted from using the threading macro to using transducers and “into”. Only the first step in ->> (the starting collection, where it comes from) and the last step in ->> (the final collection, where to put it, which was a call to “vec”) are flipped when we go to “into”; the transformation steps are pretty much the same. In their example, they combined the steps into a function with “comp”. Also: transducers go right-to-left, which is unintuitive for me.
I think you use “eduction” when you want to transduce part of a collection and not have dangling resources.
I did not understand the threading macro until I had a need for it. Perhaps transducers and eduction will be the same.
I did find a way to use the partition function to work with moving averages. You need the members of your collection to be in order from most recent to oldest. The you can get a collection of moving averages with this:
(map #(/ (reduce + %1) (count %1)) (partition 4 1 coll-most-recent-to-oldest))
Chapter 5 is about spec. Clojure seems to have a lot of concepts that are new to me, even more than the little Scheme I have worked with.
Image from the Liuthar Gospels, a tenth century manuscript created in southern Germany, currently housed in the cathedral of Aachen, assumed allowed under public domain. I have read there are 30 full-page miniatures in the manuscript, but I have not been able to find a pdf or any other pictures than the one on this page.