Search This Blog

Wednesday, December 22, 2021

Christmas Theorem: Principled Windmills

#!/usr/bin/env clojure

;; Fermats' Christmas Theorem: Principled Windmills

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Here's a bunch of code to make svg files of arrangements of coloured squares.
;; I'm using this to draw the windmills.
;; It's safe to ignore this if you're not interested in how to create such svg files.
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

(require 'clojure.xml)

(def squaresize 10)

(defn make-svg-rect [i j colour]
  {:tag :rect
   :attrs {:x (str (* i squaresize)) :y (str (* j squaresize)) :width  (str squaresize) :height (str squaresize)
           :style (str "fill:", colour, ";stroke:black;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1")}})

(defn adjust-list [rectlist]
  (if (empty? rectlist) rectlist
      (let [hmin (apply min (map first  rectlist))
            vmax (apply max (map second rectlist))]
        (for [[a b c] rectlist] [(- a hmin) (- vmax b) c]))))

(defn make-svg [objects]
  {:tag :svg :attrs { :version "1.1"  :xmlns "http://www.w3.org/2000/svg"}
   :content (for [[i j c] (adjust-list objects)] (make-svg-rect i j c))})

(defn svg-file-from-rectlist [filename objects]
  (spit (str filename ".svg") (with-out-str (clojure.xml/emit (make-svg objects)))))

(defn hjoin
  ([sql1 sql2] (hjoin sql1 sql2 1))
  ([sql1 sql2 sep]
   (cond (empty? sql1) sql2
         (empty? sql2) sql1
         :else (let [xmax1 (apply max (map first sql1))
                     xmin2 (apply min (map first sql2))
                     shift  (+ 1 sep (- xmax1 xmin2))]
                 (concat sql1 (for [[h v c] sql2] [(+ shift h) v c]))))))

(defn hcombine [& sqllist] (reduce hjoin '() sqllist))

(defn svg-file [filename & objects]
  (svg-file-from-rectlist filename (apply hcombine objects)))


(defn orange [n] (if (< n 0) (range 0 n -1) (range 0 n 1)))

(defn make-composite-rectangle [h v hsquares vsquares colour]
  (for [i (orange hsquares) j (orange vsquares)] [(+ i h) (+ j v) colour]))


;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; end of drawing code
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

;; Let's do another example in a more principled way

;; We'll think in terms of triples [s, p, n]

;; Where s is the size of the red square, p (parallel) is the width of the arms , and n (normal) is
;; the length of the arms.

;; Here's a function to draw the windmill that represents such a triple

(defn make-windmill [[s p n]]
            (let [ s2 (quot s 2)
                  is2 (inc s2)
                  ds2 (- is2)]
              (concat (make-composite-rectangle  (- s2)  (- s2) s      s     "red")
                      (make-composite-rectangle  (- s2)  is2    p      n     "white")
                      (make-composite-rectangle  s2      ds2    (- p)  (- n) "white")
                      (make-composite-rectangle  ds2     (- s2) (- n)  p     "green")
                      (make-composite-rectangle  is2     s2     n      (- p) "green"))))

(make-windmill [1 1 1]) ; ([0 0 "red"] [0 1 "white"] [0 -1 "white"] [-1 0 "green"] [1 0 "green"])

(svg-file "windmill" (make-windmill [1 1 1]))

;; As we do our windmill transformations s*s + 4 * p * n should always stay the same
(defn total [[s p n]]
  (+ (* s s) (* 4 p n)))

(total [1 1 1]) ; 5



;; So with this new way of representing things:

;; Consider 37 = 4 * 9 + 1

;; Our first triple will be

[1 1 9]

(total [1 1 9]) ; 37

;; And its windmill looks like:
(svg-file "windmill-37-1" (make-windmill [1 1 9]))
 

 
 
 ;; We can't change the size of the red square here, so the other thing we can do is to rotate the arms

;; In terms of triples, [1 1 9] -> [1 9 1]

(total [1 9 1]) ; 37

(svg-file "windmill-37-2" (make-windmill [1 9 1]))


;; Now we can change the size of the red square, it can increase to three, and that means that we have to shorten the arms by two ;; [1 9 1] -> [3 1 7] (total [3 1 7]) ; 37 (svg-file "windmill-37-3" (make-windmill [3 1 7]))
;; Note that this also changes the colour of the arms, but that doesn't matter, the only reason the ;; arms are two different colours is to make it easier to see what's going on. If it bothers you ;; just go and change white to green in the windmill code! ;; From [3 1 7] the only change we can make to the size of the red square is to put it back to one ;; So instead, we'll swap the arms again ;; [3 1 7] -> [3 7 1] (total [3 7 1]) ; 37 (svg-file "windmill-37-4" (make-windmill [3 7 1]))
;; Now, swapping the arms just moves us back a step, but we can increase the size of the red square to five ;; and shorten the arms by two ;; [3 7 1] -> [5 1 3] (total [5 1 3]) ; 37 (svg-file "windmill-37-5" (make-windmill [5 1 3]))
;; Again, the only way to change the size of the red square is to put it back, so let's rotate arms ;; I'm going to call changing the size of the red square the red transformation ;; and rotating the arms the green transformation ;; The green transformation is easy to express in terms of triples (defn green [[s p n]] [s n p]) (green [5 1 3]) ; [5 3 1] (total [5 3 1]) ; 37 (svg-file "windmill-37-6" (make-windmill [5 3 1]))
;; Now, the green transformation just puts us back a step, and it looks like we can't increase the size ;; of the red square, so are we stuck? ;; No! If you stare at the diagram for long enough, you'll see that we can *reduce* the size of the ;; red square instead of increasing it, growing the arms inward until the red shape is square again. ;; And in fact that's our only possible move. ;; [5 3 1] -> [1 3 3] (svg-file "windmill-37-7" (make-windmill [1 3 3]))
;; It's kind of annoying that this flips the shape! But it's obviously still the same total number ;; of squares, so just like with the colour flip I'm going to ignore that for now rather than ;; introduce unnecessary complexity to the drawing code ;; I'm going to call both reducing and increasing the size of the red square a "red transformation", ;; and the red transformation is going to need a parameter to say how much to change the size of the ;; square ;; Let's say, as above, that we want to shift the boundaries of the big red square in by two small unit squares ;; so say delta = -2 ;; that means that the new red square is size one, five less two squares on either edge ;; that means that the red square has changed from size twenty-five to size one ;; that leaves twenty-four spare squares, to be distributed between the four arms ;; which is six spare squares per arm ;; since we're just moving the boundary of the square, or alternatively extending the arms into the ;; square, that doesn't change p, the width of the arm parallel to the square ;; so we add the six squares in rows of p. ;; in our example above, p is three, so those six squares result in the arms lengthening by two ;; In code (defn red [[s p n] delta] (let [news (+ s (* 2 delta)) spare (- ( * s s ) (* news news)) sparesperarm (/ spare 4) lengthchange (/ sparesperarm p)] [news (+ n lengthchange) p])) (total [5 3 1]) ; 37 (red [5 3 1] -2) ; [1 3 3] (total (red [5 3 1] -2)) ; 37 (svg-file "windmill" (make-windmill [5 3 1 ])) ; nil (svg-file "windmill" (make-windmill (red [5 3 1] -2))) ; nil (svg-file "windmill-37-7" (make-windmill [1 3 3])) 
 
;; Now we have a real problem. The only red transformation we can make is to go back a step, but
;; the green transformation does nothing useful here:

(green [1 3 3]) ; [1 3 3]


;; But every problem is an opportunity, as they say:

;; We can split up the rectangle
(svg-file "windmill-37-split"
          (make-composite-rectangle 0 0 1 1 "red")
          (make-composite-rectangle 0 0 3 3 "green")
          (make-composite-rectangle 0 0 3 3 "green")
          (make-composite-rectangle 0 0 3 3 "white")
          (make-composite-rectangle 0 0 3 3 "white"))
          
          
(svg-file "windmill-37-recombine" (make-composite-rectangle 0 0 1 1 "red") (concat (make-composite-rectangle 0 0 3 3 "green") (make-composite-rectangle 3 3 3 3 "green") (make-composite-rectangle 0 3 3 3 "white") (make-composite-rectangle 3 0 3 3 "white")))
;; The green transformation fails if and only if the arms are squares, and if the arms are squares, we can ;; combine them to form one big even square (svg-file "windmill-37-final" (make-composite-rectangle 0 0 1 1 "red") (concat (make-composite-rectangle 0 0 6 6 "green")))
;; So 37 = 1*1 + 6*6 ;; Which is what we're trying to show, thirty-seven is the sum of one odd and one even square

Sunday, December 19, 2021

Fermat's Christmas Theorem: Windmills

#!/usr/bin/env clojure

;; Fermats' Christmas Theorem: Windmills

;; Sorry for the delay, I had COVID. I'm fine, don't worry!

;; Let's pick an arbitrary number of the form 4n+1, say 29

;; Precisely because it's of form 4n+1, we can split it into a central square and four identical
;; blocks, in this case, a 1x1 square and four 1x7 blocks

;; 29 = 1*1 + 4 * (1 * 7)
(+ (* 1 1) (* 4 (* 1 7))) ; 29

;; Let's draw that:

;; I'm not going to explain how the svg making thing works, but see:
;; http://www.learningclojure.com/2010/10/generating-xml-to-make-svg-vector.html
;; if you're curious about the details 

(require 'clojure.xml)

(def squaresize 10)

(defn make-rect [i j colour]
  {:tag :rect
   :attrs {:x (str (* i squaresize))
           :y (str (* j squaresize))
           :width  (str squaresize)
           :height (str squaresize)
           :style (str "fill:", colour, ";stroke:black;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1")}})


;; SVG coordinates have 0,0 in the top left corner, whereas I like my origin in the middle,
;; and with the vertical component increasing as we go up, so this is a coordinate transform
;; That converts my system to SVG's system.
(defn adjust-list [rectlist]
  (let [hmin (apply min (map first  rectlist))
        vmax (apply max (map second rectlist))]
    (for [[a b c] rectlist] [(- a hmin) (- vmax b) c]))) 

(defn make-svg [objects]
  {:tag :svg
   :attrs {:width "100%"
           :height "100%"
           :version "1.1"
           :xmlns "http://www.w3.org/2000/svg"}
   :content (for [[i j c] (adjust-list objects)] (make-rect i j c))})

(defn svg-file [filename objects]
  (spit (str filename ".svg") (with-out-str (clojure.xml/emit (make-svg objects)))))

(defn orange [n]
  (if (< n 0)
    (range 0 n -1)
    (range 0 n 1)))

(defn make-composite-rectangle [h v hsquares vsquares colour]
  (for [i (orange hsquares) j (orange vsquares)] [(+ i h) (+ j v) colour]))


;; With this drawing code in hand we can diagram 29 = 1 * 1 + 4 * (1 * 7)

;; As this windmill shape:
(svg-file "windmill-29-1" 
          (concat (make-composite-rectangle  0  0   1   1 "red")
                  (make-composite-rectangle  1  0   7   1 "white")
                  (make-composite-rectangle -1  0  -7  -1 "white")
                  (make-composite-rectangle  0  1  -1   7 "green")
                  (make-composite-rectangle  0 -1   1  -7 "green")))




;; Or alternatively we could show it as 29 = 1*1 + 4 * (1 * 7) (svg-file "windmill-29-2" (concat (make-composite-rectangle 0 0 1 1 "red") (make-composite-rectangle 1 0 1 7 "white") (make-composite-rectangle -1 0 -1 -7 "white") (make-composite-rectangle 0 1 -7 1 "green") (make-composite-rectangle 0 -1 7 -1 "green")))
;; Now we notice that there's a 3x3 square in the middle, so what about: (svg-file "windmill-29-3" (concat (make-composite-rectangle -1 -1 3 3 "red") (make-composite-rectangle 1 2 1 5 "white") (make-composite-rectangle -1 -2 -1 -5 "white") (make-composite-rectangle -2 1 -5 1 "green") (make-composite-rectangle 2 -1 5 -1 "green")))
;; Which is equivalent to 29 = 3*3 + 4* (1 * 5) ;; And then of course we can flatten the arms again: ;; 29 = 3*3 + 4 * ( 5 * 1 ) (svg-file "windmill-29-4" (concat (make-composite-rectangle -1 -1 3 3 "red") (make-composite-rectangle 1 2 -5 1 "white") (make-composite-rectangle -1 -2 5 -1 "white") (make-composite-rectangle -2 1 1 -5 "green") (make-composite-rectangle 2 -1 1 5 "green")))
;; And we see a 5*5 square now, so ;; 29 = 5*5 + 4 * ( 1 * 1) (svg-file "windmill-29-5" (concat (make-composite-rectangle -2 -2 5 5 "red") (make-composite-rectangle -3 2 -1 1 "white") (make-composite-rectangle 3 -2 1 1 "white") (make-composite-rectangle -2 -3 1 -1 "green") (make-composite-rectangle 2 3 1 1 "green")))
;; Notice now that our diagram is one big odd square, and four little squares ;; Four little squares can be combined into one big even square ;; 4*1*1 is also equal to 2*2*1*1, = (2*1)*(2*1) = 2*2 ;; so 29 = 5*5+2*2 ;; Which is to say that 29, a prime number of form 4n + 1, is equal to the sum of an odd and an even square. ;; 29 = 25 + 4 ;; These windmill drawings form the core of the proof of the Christmas Theorem. Try the technique out on some other numbers!

Friday, December 3, 2021

A Festive Theorem

#!/usr/bin/env clojure

;; A Festive Theorem

;; About a week ago, a friend of mine who is not noted for his interest in pure mathematics, and
;; whose identity I will conceal behind the alias "Sipper" caught me in the Wetherspoons and showed
;; me a number theory proof (or at least most of one, we couldn't actually finish the argument off)

;; I've never been interested in number theory. It seems both useless and boring, but the central
;; idea of this proof was intriguing, so today I sat down, again in Wetherspoons, with quite a lot
;; of paper and coffee and an all-day brunch (all for £7.30, I love Spoons, if you want to advertise
;; on this blog just get in touch), and hammered the damned thing out until I was happy with it.

;; The proof's really visual and beautiful, but not constructive, but it suggested an algorithm to
;; me, so I'm going to try to get that algorithm working, and then show why it works by visualizing
;; what it's doing.

;; I have no idea whether anyone will find this interesting, but since it's the only thing in all of
;; number theory that's ever struck me as worth knowing, and Sips found it interesting too, I'm going
;; to write it up.

;; In this first bit, a statement of the Theorem, which itself took me a while to get my head round.

;; make the repl stop after the first 20 elements of a sequence
(set! *print-length* 20)

;; If you square an even number, then it will be divisible by 4
;; But if you square an odd number, then it will leave a residue of 1 mod 4

(defn square [x] (* x x))
(def mod4 #(rem % 4))

(map mod4 (map square (range)))  ;; (0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 ...)

;; If that's not obvious, think about it for a few minutes and see whether you can make it so....

;; This means that if you take an even and an odd number, and square them, and add the squares, then
;; the residue mod 4 will always be 1

(mod4 (+ (square 2)  (square 5)))     ;; 1    ( 2*2 + 5*5 = 29 = 28 + 1 = 4 * 7 + 1)
(mod4 (+ (square 10) (square 17)))    ;; 1    (etc)

;; Let's check this is actually true for lots of numbers:

(def naturals (map inc (range))) ;; (1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 ...)

(defn odd [n] (- (* 2 n) 1))
(def odds (map odd naturals))   ;; (1 3 5 7 9 11 13 15 17 19 21 23 25 27 29 31 33 35 37 39 ...)

(defn even [n] (* 2 n))
(def evens (map even naturals)) ;; (2 4 6 8 10 12 14 16 18 20 22 24 26 28 30 32 34 36 38 40 ...)

;; Here are all possible pairs of natural numbers
(def pairs (for [sum naturals i (take (dec sum) naturals)] (list i, (- sum i)))) ;; ((1 1) (1 2) (2 1) (1 3) (2 2) (3 1) (1 4) (2 3) (3 2) (4 1) (1 5) (2 4) (3 3) (4 2) (5 1) (1 6) (2 5) (3 4) (4 3) (5 2) ...)

;; From which we can construct all odd-even pairs
(def odd-even-pairs (for [[i,j] pairs] (list (odd i) (even j)))) ;; ((1 2) (1 4) (3 2) (1 6) (3 4) (5 2) (1 8) (3 6) (5 4) (7 2) (1 10) (3 8) (5 6) (7 4) (9 2) (1 12) (3 10) (5 8) (7 6) (9 4) ...)

;; From which we can construct all sums of squares of odd and even numbers
(def odd-even-squares (for [[i,j] odd-even-pairs] (+ (square i) (square j)))) ;;(5 17 13 37 25 29 65 45 41 53 101 73 61 65 85 145 109 89 85 97 ...)

;; paranoid check, if I did that right they should all be 1 mod 4
(map mod4 odd-even-squares) ;; (1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 ...)


;; So, since both : it's obvious ; and also it looks like it might actually be true, I think we can take it to the bank that:

;; If o is an odd number, and e is an even number, then o*o+e*e is 1 mod 4

;; This has apparently been pretty obvious to everyone who's ever thought about it, and is just one
;; of those number-theory facts that always seem to fascinate people who aren't me.

;; But it occurred to Albert Girard in 1632 to wonder if the converse was true:

;; If you have a number that is 1 mod 4, can you always split it into odd and even squares?

;; Let's look for counterexamples:
(def early-ones (sort (take 10000 odd-even-squares))) ;; (5 13 17 25 29 37 41 45 53 61 65 65 73 85 85 89 97 101 109 113 ...)

(def candidates (map #(+ (* 4 %) 1) naturals)) ;; (5 9 13 17 21 25 29 33 37 41 45 49 53 57 61 65 69 73 77 81 ...)


;; This is such a hack, I am shame....
(require 'clojure.set)
(clojure.set/difference (set (take 100 candidates)) (set early-ones)) ;; (9 21 33 49 57 69 77 81 93 105 121 129 133 141 161 165 177 189 201 209 ...)

;; So it looks like the converse is not true.

;; 9, for instance, is 4*2+1, so it's a candidate, but it looks like you can't split it into odd and even squares.
;; Let's try by hand, just going through all the possible odd numbers

;; 9 = 1*1 + 8 ; 8 is not the square of anything
;; 9 = 3*3 + 0 ; 0 is not the square of a natural number

;; This seems a bit dodgy to me, 9 = 3 * 3 + 0 * 0, so does it work if we count 0 as an even number? This will turn out not to matter too much.....

;; Look at 21
;; 21 = 1*1 + 20 ; 20 is not the square of anything
;; 21 = 3*3 + 12 ; 12 is not the square of anything
;; 21 = 5*5 - 4  ; oops, 5*5 is too big, although it does look like 21 = 5*5 - 2*2, but that wasn't the question. Sum of squares, not difference of squares.

;; OK 33 then
;; 33 = 1*1 + 32 ; 32 is not the square of anything
;; 33 = 3*3 + 24 ; 24 is not the square of anything
;; 33 = 5*5 + 8  ;  8 is not the square of anything
;; 33 = 7*7 - 16 ; oh bloody hell, 33 = 7*7 - 4*4

;; Anyway, that's not the question. Neither 21 nor 33 are the sum of two squares., even though 21 = 5*4+1 and 33 = 4*8+1

;; Looking at the list of the ones that did work
early-ones ;; (5 13 17 25 29 37 41 45 53 61 65 65 73 85 85 89 97 101 109 113 ...)

;; One might notice that there are an awful lot of prime numbers on that list. (although they're not all primes....)

;; In fact
(defn divisors [n] (filter #(= 0 (rem n %)) (map inc (range n))))

(divisors 12) ;; (1 2 3 4 6 12)

(defn prime? [n] (= (count (divisors n)) 2))
(filter prime? (range 200)) ;; (2 3 5 7 11 13 17 19 23 29 31 37 41 43 47 53 59 61 67 71 ...)


(def candidate-primes (filter prime? candidates)) ;; (5 13 17 29 37 41 53 61 73 89 97 101 109 113 137 149 157 173 181 193 ...)

(clojure.set/difference (set (take 100 candidate-primes)) (set early-ones)) ;; #{}

(clojure.set/difference (set (take 1000 candidate-primes)) (set early-ones)) ;; #{}

;; If there's a prime of form 4*n+1 that isn't the sum of one odd and one even square, then it's fairly big

;; It looks as though, at least for the first thousand candidates, if a number is both prime, and of form 4*n+1,
;; then it is expressible as an even square plus an odd square.

;; Albert Girard, in 1632, presumably after a fair amount of dicking about with bits of paper,
;; conjectured that this might be so for all candidate primes.

;; On December 25th 1640, Pierre de Fermat wrote to his friend Marin Mersenne that he had proved
;; that this was true, but he did not trouble to include the proof or indeed ever tell anyone how he
;; did it.

;; On the 12th of April 1749, Leonhard Euler wrote to his friend Christian Goldbach that he had
;; proved that this was true, and then actually went and published his (intricate and difficult) proof.

;; In recognition of Fermat's invaluable contribution, this result is universally known as

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;;             Fermat's Christmas Theorem.
;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

;; Let p be a prime number

;; Then p is expressible as the sum of odd and even squares
;; if and only if p is 4*n+1 for some natural number n








Thursday, December 2, 2021

A test program

#!/usr/bin/env clojure

;; It looks like clojure has become a full citizen of Debian

;; In emacs, a syntax highlighted program can be converted to html with htmlize-buffer, and then if
;; you top and tail that and copy it to blogger it comes up nicely. And this seems to still be
;; working after all this time

;; So here is my first published clojure program for a while...

;; If you're using Debian 11, you can run it by installing clojure with
;; $ sudo apt install clojure

;; saving this file as test.clj

;; and then in a terminal window making the file executable
;; $ chmod +x test.clj
;; and then running it
;; $ ./test.clj

(println "hello")

(defn factorial [n]
  (if (< n 1) 1
      (* n (factorial (- n 1)))))

(println '(factorial 10) (factorial 10))

;; If all is working then you should see something like
;; $ ./test.clj
;; hello
;; (factorial 10) 3628800

Emacs, even

The truly terrifying bit of getting any language to work on your machine is getting it to work with EMACS. 

Last time I tried to get clojure working, this was the stage that I gave up at. Everything was just broken, and so I wrote the program I was going to write in python instead.

But all it took this time was:

(Emacs 27.1, the version that comes with Debian 11/Bullseye)

M-x package install

clojure-mode

(churn)

and then I can load my test.clj program from earlier, and it's syntax highlighted. 

M-x package-list-packages

tells me that it's clojure-mode 5.13.0, from melpa-stable .

I can save the program, and run 

./test.clj 

from the command line in a terminal, and it just works, with a slightly irritating 2 second delay.

I might hope for more:

I remember once I could do things like putting the cursor in an expression and pressing Alt-Ctrl-x to evaluate that expression in a running REPL.

but this will do for now. 

I can always copy and paste things to a REPL, after all.


Clojure Shell Scripts on Debian

So I managed to install a very recent clojure through Debian's package manager, and it just worked.

And my next thought is: "If it's somehow become a proper part of Debian, does that mean I can do shell scripts?"

so

cat >test.clj

#!/usr/bin/env clojure
(print "hello")

chmod +x test.clj

./test.clj

(2 second pause...)

hello

Compare with the python equivalent:

cat >test.py

#!/usr/bin/env python
print("hello")


chmod +x test.py

./test.py
hello

The only difference is the lack of a two second pause. Python responds instantly.

I can live with a two second pause.

I am totally amazed and pleased by this. It feels much more like a proper programming language than it used to. It's too good to be true.

I wonder if we've got a command line argument parser yet.

Hello Again World (2nd December 2021) Setting Up Clojure on Debian 11

It's been a while since I've used Clojure, and I've upgraded my system a fair bit since then, so I'm going to try to start again from scratch.


My computer is running latest stable Debian

cat /etc/debian_version
11.1

(version 11.1, aka bullseye)

My first instinct is to install via the package manager:

apt search clojure

clojure/stable,now 1.10.2-1 all
  Lisp dialect for the JVM

clojure.org tells me that the latest version is 1.10.3, so the debian version will do.

sudo apt install clojure

clojure
Clojure 1.10.2
user=> 

That seems far too easy, does it work? 

First, can I do hello world at all?

user=> (print "hello")
hellonil

user=> (defn factorial [n] (if (< n 2) n (* n factorial (- n 1))))

#'user/factorial

user=> (factorial 10)
Execution error (ClassCastException) at user/factorial (REPL:1).
class user$factorial cannot be cast to class java.lang.Number (user$factorial is in unnamed module of loader clojure.lang.DynamicClassLoader @56ccd751; java.lang.Number is in module java.base of loader 'bootstrap')

Oh my God, what???

.....stares in bewildered disbelief and starts cursing Java and its pointless verbose complexity before seeing the problem and feeling silly...

user=> (defn factorial [n] (if (< n 2) n (* n (factorial (- n 1)))))
#'user/factorial
user => (factorial 10)
3628800


So that looks great, and it was very easy. Things have improved hugely since I last tried this!

I could hope for better error messages, something like 'can't multiply a number by a function' would have been more helpful.


 


 






Followers