`open(FH, 'filename') || die;`

and have to force myself to use the more modern `open(my $fh, '<', 'filename')`

with its lexically scoped filehandle.
I have been programming Perl for 12 years or so, but aside from one conference (YAPC Muenchen 2002) I’ve never really immersed myself in the community. For this reason, I think I have missed out on quite a few niceties. Moose, DBIx and other modules bring Perl up to the level of its contemporaries **if you don’t need to work with people who are not using them**. I only came across POE recently (which I keep mentioning because it is so awesome).

Heck, even C++ has boost.

or DSLs I think they call it.

Ray Dillinger once pointed out that people write scheme in a variety of incompatible styles because the substrate isn’t pleasant for programming on directly. But it is possible to layer any sugar you like on it. This leads to a bunch of different and practically incompatible styles.

Anyway, what I see is that scheme programmers are capable of

doing a heck of a lot as individuals, and are very happy with

the personally-customized language they each work with. But

they tend not to work together on large projects because of

the cognitive overhead of learning each other’s personally-

customized languages, which may have different or conflicting

definitions.Common Lisp programmers, by contrast, have a lot of standard

libraries and tend to forgive or ignore some small things that

may not fit perfectly with their personal style. But they do

work together on large projects, because they all have the same

set of language extensions and they can read each other’s code.

I still find eager comprehensions about the nicest way of specifying nested loops that I’ve seen. Perl syntax tweaking dudes: if you add these, I’ll never switch! What’s that? Fix it myself? It is easier to move to python or ruby I think.

Is it a coincidence that languages with fixable syntax (Lisp, Perl, Tcl, Ocaml) have ‘lost’ to those with a fixed syntax (Java, Python)? Ruby dudes beware.

There have been a few posts floating around the blogosphere talking about writing posts supporting perl. I put my own effort into doing something similar for Emacs. However, in my opinion, Emacs needs the help and Perl does not.

Emacs could be greatly improved if there were many more Emacs Lisp hackers creating libraries and writing examples and documentation. Perl already has all of those things. <strike>As</strike> If its popularity wanes, what is lost? I guess people are thinking about job opportunities and stuff like that, but I suspect that the outflow of former Perl programmers will outpace the loss of Perl jobs.

Oh yes, Emacs-using Perl dudes, please add eager comprehensions to Perl and write Emacs blog posts rather than Perl ones. Thank you.

1. Even though I’m not really a casual Perl user. I do this stuff *professionally* don’t you know

Futzing around with Project Euler is something I do for fun. Most recently I was looking at problem 73 – count the reduced proper fractions with a denominator less than or equal to 10,000 between 1/3 and 1/2.

Emacs Lisp is usually my default language for doing this kind of thing as I’m already in my text editor and there is a REPL to experiment with.

First of all, it is clear that I’m going to need a function to calculate the greatest common divisor. I found an imperative Pascal implementation of Euclid’s algorithm here. A brief aside – I searched for Pascal deliberately as I generally find it very clear. Does anyone else do that?

(defun gcd (a b) (while (not (= b 0)) (let ((tmp b)) (setq b (% a b)) (setq a tmp))) a)

Thinking ahead, I’ll probably know what the gcd is before we call make-fraction as only fractions with a gcd of 1 will be actually counted amongst the solutions. I’ve therefore made gcd an optional parameter as a nod to efficiency.

(defsubst make-fraction (num denom &optional gcd) (unless gcd (setq gcd (gcd num denom))) (cons (/ num gcd) (/ denom gcd)))

I like the flexibility that lisp-like languages give you to name your functions too.

(defsubst more-than-1/3 (frac) (let ((num (car frac)) (denom (cdr frac))) (> (* num 3) denom))) (defsubst less-than-1/2 (frac) (let ((num (car frac)) (denom (cdr frac))) (< (* num 2) denom))) (defsubst within-range (frac) (and (more-than-1/3 frac) (less-than-1/2 frac)))

We only check fractions between 1/3 and 1/2 as to do all fractions with a denominator <= 10,000 would take far too long.

(defun solve-it (max-denom) (insert (format-time-string "\n\nStarted at: %H:%M:%S\n\n")) (let (num denom frac max gcd solutions) (setq solutions 0) (setq denom 2) (while (<= denom max-denom) (setq num (/ denom 3)) (setq max (1+ (/ denom 2))) (while (<= num max) (setq gcd (gcd num denom)) (when (= gcd 1) (setq frac (make-fraction num denom gcd)) (when (within-range frac) ;; (insert (format "%s\n" frac)) (incf solutions))) (incf num)) (incf denom) (when (= (% denom 50) 0) (insert (format "Denom: %d Solutions: %d\n" denom solutions))) (sit-for 0)) (insert (format "\n%d solutions\n" solutions)) (insert (format-time-string "Finished at: %H:%M:%S\n"))))

After I wrote this, I realised I didn’t need to construct and destruct my fraction type so simplified to the following:

(defun solve-it (max-denom) (insert (format-time-string "\n\nStarted at: %H:%M:%S\n")) (let (num denom frac max solutions) (setq solutions 0) (setq denom 5) (while (<= denom max-denom) (setq num (1+ (/ denom 3))) (setq max (/ denom 2)) (while (<= num max) (when (= (gcd num denom) 1) (incf solutions)) (incf num)) (incf denom)) (insert (format "%d solutions\n" solutions)) (insert (format-time-string "Finished at: %H:%M:%S\n")))) (solve-it 10000) ;; Started at: 22:14:35 ;; 5066251 solutions ;; Finished at: 22:15:45

70 seconds. Okay.

The most annoying thing is the primitive looping constructs. `while`

is the basic and obvious built-in. It also has a slew of macros beginning with `doXXX`

including `dotimes`

and `dolist`

not to mention the mighty common lisp `loop`

macro.

I don’t know loop (but I’m going to learn it), but after messing about with `do*`

for a few minutes, I realised it wasn’t the looping construct for me.

(do* ((i 5 (if (> j 10) (+ i 1) i)) (j (+ i 1) (if (> j 10) (+ i 1) (+ j 1)))) ((> i 10)) (insert (format "[%d %d]" i j)))

**Yuck.**

Now, the great thing about lisp is supposed to be that if you don’t like the syntax you can add your own with macros. Unfortunately, I haven’t got around to that yet as a bunch of people have already designed most of the syntax I like.

When I read some of the earlier posts on this blog, it seems that *scheme* has got some nice generator syntax (aka eager comprehensions) for handling nested loops.

There are a nice set of posts on eager comprehensions here.

I took `print-ln`

from the portable scheme post and `gcd`

from SICP.

#lang scheme/base (require srfi/42) (define (print-ln . args) (for-each display args) (newline) (flush-output)) (define (gcd a b) (if (= b 0) a (gcd b (remainder a b)))) (define (solve-it max-denom) (sum-ec (:range denom 2 (+ max-denom 1)) (:range num (+ (floor (/ denom 3)) 1) (ceiling (/ denom 2))) (if (= (gcd num denom) 1) 1 0))) (print-ln "There are " (solve-it 10000) " solutions")

Yikes, mzscheme is much quicker than emacs-lisp. That surprised me. A factor of 10 I would have expected, a factor of 50 not so much.

$ time mzscheme frac.scm There are XXX solutions real 0m1.413s user 0m1.404s sys 0m0.004s

use strict; use warnings; use POSIX qw(floor ceil); sub gcd { my ($n1, $n2) = @_; until ($n2 == 0) { my $tmp = $n2; $n2 = $n1 % $n2; $n1 = $tmp; } return $n1; }

The nested loop actually looks okay to me in perl although not as nice as the srfi-42 eager comprehensions.

sub solve_it { my $max_denom = $_[0]; my $solutions = 0; foreach my $denom (5..$max_denom) { my $max = ceil($denom / 2) - 1; foreach my $num ((1 + floor($denom / 3))..$max) { if (gcd($num, $denom) == 1) { ++$solutions; } } } return $solutions; } printf "There are %d solutions\n", solve_it(10000);

The performance of my perl is pretty bad too.

$ time perl frac.pl There are XXX solutions real 0m47.026s user 0m46.963s sys 0m0.008s

let rec gcd a b = if b = 0 then a else gcd b (a mod b);; let solve_it max_denom = let rec loop num denom solutions = if denom > max_denom then solutions else if num >= (denom/2+1) then loop ((denom+1)/3+1) (denom+1) solutions else begin if gcd num denom = 1 then begin (* Printf.printf "%d/%d\n" num denom; *) loop (num+1) denom (solutions+1) end else loop (num+1) denom solutions end in loop ((5/3)+1) 5 0;; Printf.printf "There are %d solutions\n" (solve_it 1000);;

Oh dear, I seem to have an awful accent when programming ocaml. I’ll need to work on that.

$ time ./a.out There are XXX solutions real 0m1.071s user 0m1.060s sys 0m0.004s

For this particular task (looping and integer math) Emacs Lisp is slow, but not that slow compared with another scripting language. I really like the scheme looping constructs and mzscheme is surprisingly quick (again, just for this tiny thing), not too far from the ocaml – although again I should emphasise that the ocaml is a terrible hack. And finally, I need to learn how to use `loop`

properly.

All comments welcome.

]]>