Feeds:
Posts
Comments

Archive for May, 2009

Loops in Ocaml

Following on from my look at basic looping syntax in various languages I thought I’d take a look at various methods of looping in Ocaml to make amends for the Ocaml solution.

gcd is the same as in the previous post.

let rec gcd a b =
  if b = 0 then a
  else gcd b (a mod b);;

Using one function for one loop is nicer than cramming both into one which felt too much like coding using if and goto.

Most of the solutions use the following recursive function.

let count_for_denom denom =
  let rec loop num count =
    if num >= (denom/2+1) then count
    else loop (num+1) (count + if gcd num denom = 1 then 1 else 0)
  in
    loop (denom/3+1) 0;;

The first solution is a pure recursive function. This is really just mental masturbation – needlessly exchanging loops for more verbose recursion.

let solve_it max_denom =
  let rec loop denom count =
    if denom > max_denom then count
    else loop (denom+1) count+count_for_denom denom
  in
    loop 5 0;;

Printf.printf "%d solutions\n" (solve_it 10000);;

$ time ./a.out
XXX solutions

real    0m1.138s
user    0m1.108s
sys     0m0.000s

Functional programming includes a bunch of higher level functions such as map and fold. In a strict language it would be wasteful to construct a list before iterating over it with one of these higher-order functions.

How about a fold-like function that folds over a range of numbers?

let collector s e acc f =
  let rec loop s acc =
    if s > e then acc
    else loop (s+1) (f acc s)
  in loop s acc;;

Printf.printf "%d solutions\n"
  (collector 5 1000 0 (fun acc denom -> acc+count_for_denom denom));;

Here is one with a reference and a for next loop. I think this is quite nice – I like that Ocaml is a pragmatic language and includes this kind of stuff.

let count = ref 0 in
  for i = 5 to 1000 do
    count := !count + count_for_denom i
  done;
  Printf.printf "%d solutions\n" !count;;

And finally the pure nested for loop solution which is about 20% faster than the recursive versions.

let count = ref 0 in
  for i = 5 to 10000 do
    for j = (i/3+1) to (i/2) do
      if gcd i j == 1 then count := !count + 1
    done
  done;
  Printf.printf "%d solutions\n" !count;;

$ time ./a.out
XXX solutions

real    0m0.934s
user    0m0.928s
sys     0m0.004s

So, is there anything I missed? What other types of loops are there in Ocaml?

Read Full Post »

Okay, this post is going to be quite long. I’m going to start with a basic problem I was solving in emacs lisp. From there I’ll segue into thinking about looping syntax and finally I’ll do a bit of benchmarking as I’ve got the code already and people seem to like that (the scheme, ocaml, c++ speed comparison is by far the most popular post on this blog followed by this).


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 Solution

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.

Scheme Solution

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

Perl Solution

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

Ocaml Solution

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

So, Conclusions

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.

Read Full Post »

Useful Blog Comments

Nachopp demonstrates some emacs lisp that inserts a commonly used find command in a shell buffer. And Ian Eure has a great follow-up comment which demonstrates the more typical way of defining emacs lisp functions; talks about alternatives such as abbrev mode and yasnippet and finally mentions the best solution, the built-in rgrep.

Defining C++ styles

David Ha has a gallery of some of the built-in C++ styles. None of the styles suit me exactly so I have accreted a fair amount of C++ configuration code over the years. I must admit, I haven’t audited for ages so I’m not sure which bits are necessary and which are not.

(defconst *my-cc-style*
  '((c-basic-offset . 4)
    (c-comment-only-line-offset . 0)
    (c-hanging-braces-alist . ((brace-list-open)
                               (brace-entry-open)
                               (substatement-open after)
                               (block-close . c-snug-do-while)))
    (c-cleanup-list . (brace-else-brace))
    (c-offsets-alist . ((statement-block-intro . +)
                        (knr-argdecl-intro     . 0)
                        (substatement-open     . 0)
                        (substatement-label    . 0)
                        (innamespace           . 0)
                        (case-label            . +)
                        (statement-cont        . +)))))

(defun my-c-initialization-hook ()
  (define-key c-mode-base-map "\C-m" 'c-context-line-break)
  (define-key c-mode-base-map (kbd "RET") 'newline-and-indent)
  (define-key c-mode-base-map [f7] 'run-compile))

(add-hook 'c-initialization-hook 'my-c-initialization-hook)
(setq c-offsets-alist '((member-init-intro . ++)))

(c-add-style "PERSONAL" *my-cc-style*)

(defun my-c-mode-common-hook ()
  (c-set-style "PERSONAL")
  (setq tab-width 4
        indent-tabs-mode nil
        c-hungry-delete-key t)
  (c-toggle-auto-newline 1))

(add-hook 'c-mode-common-hook 'my-c-mode-common-hook)

The most useful commands for finding out which of the variables to set are C-c C-o (c-set-offset) and C-c C-s (c-show-syntactic-information)

This is kinda interesting where Ronnie Collinson (from the NotThinking blog)
removes the *compilation* buffer if the compile is successful. It isn’t something I personally would use as I like the feedback, but I wasn’t previously thinking about compilation-finish-functions and I have a few ideas of things I would like to run after a successful compile.

Perennial Emacs Blog Topics

There are a few perennial blog topics in the emacs world – I mentioned a smooth scrolling post in my links from 2009/17 and here is Da Zhang’s take (does anyone like the default behaviour by the way?). I included a link to a post on the incredibly useful mark ring in emacs-links-2009-09 and here is another from yesterday.

Proposed solutions – fix the smooth scrolling behaviour so it works nicely out of the box and… well, perhaps blogs are not a great way of educating the masses after all. Pity.

Read Full Post »

Some time ago, I wrote about doing batch processing of text with an external process running, e.g. Perl. Similarly, emacs-lisp has a lot of functionality for manipulating text.

The Problem

I have a file like this:

John James,Admin,other data,...
Dave Jones,Sales,...
Lisa Sims,IT,...
...

I want to convert it into the following1:

AND name IN ("Dave Jones", "John James", "Lisa Sims")
AND dept IN ("Admin", "IT", "Sales")

The Solution

First of all I need a helper function that converts lisp lists into a quoted comma-separated list.

(defun make-csv (seq)
  (mapconcat (lambda (e) (format "\"%s\"" e)) seq ", "))

And then I can iterate over the text with re-search-forward, collecting the matched strings. At the end, I’ll output the collected strings. in a sql clause fragment.

(defun process-lines (&optional begin end)
  (interactive "r")
  (goto-char begin)
  (let (names depts)
    (while (re-search-forward "\\([^,]+\\),\\([^\n,]+\\)" end t)
      (push (match-string 1) names)
      (push (match-string 2) depts)
      (next-line))
    (insert (format (concat "\n"
                            "AND name IN (%s)\n"
                            "AND dept IN (%s)\n")
                    (make-csv (sort names #'string-lessp))
                    (make-csv (sort depts #'string-lessp))))))

If you liked this post, why not subscribe to my RSS feed.


1. Okay, you got me, I don’t really want to convert it into this. But for the purpose of the example, this will do. Exercise for the reader – how can I convert it into sql that will efficiently extract just the lines I want?

Read Full Post »

When writing a muse file it always annoyed me when I have written (for example) a-really-long-variable somewhere else in the file and then when I type =a-rea and press M-/ it fails to expand.

The way to fix this behaviour is by setting dabbrev-abbrev-skip-leading-regexp

(setq dabbrev-abbrev-skip-leading-regexp "[=*]")

(Edit: fixed the first regex per Billy’s comment below. Thanks)

Okay, you think, this doesn’t affect me – I don’t use muse (why not?) How about if you’re writing some html/xml.

(setq dabbrev-abbrev-skip-leading-regexp "[^ ]*[<>=*]")

Now <strong>long-word- completes as you would expect.

There is also dabbrev-abbrev-char-regexp if you want even more control over what should be considered a match.

Also, I’m no longer using autocomplete as I find vanilla dabbrev nicer to use.

Read Full Post »

A little while ago we were talking about clients and servers. And I’ve finally got back to the interesting thing which is playing with emacs networking.

The comment from Gabriel nicely pointed out emacs’ low-level socket facilities.

(open-network-stream) which is synchronous and
(make-network-process) which can be asynchronous if the parameter is set. I haven’t been able to make the last one work, but check it out yourself.

So, er, I’m not 100% sure how to simulate a crappy internet connection. Maybe making my server pause 2 seconds between line reads will be sufficient.

sub process_request
{
    while () {
        s/\r?\n$//;
        print STDERR "Received [$_]\n";
        last if /quit/i;
        sleep 2;
    }
}

I’m also interested (or perhaps curious?) in when the connection is made and broken.

sub post_accept_hook
{
    print STDERR "Accepted new connection\n";
}

sub post_process_request_hook
{
    print STDERR "Client disconnected\n";
}

Did I mention I think Perl’s bad press is a little unfair?

So what I need now is a basic API for connecting, disconnecting and sending messages. make-network-process makes a process as you can probably infer from the name and for my purposes a single client is enough so I make a wrapper to get the current process. Layering in this way means I can add any error handling at the appropriate point later on. And also it should be fairly easy to generalise client-process to choose between different connections.

(defconst client-process-name "*client*")
(defsubst client-process () (get-process client-process-name))

For maximum asynchronicity we add a sentinel function that will be called back when the connection has completed, either successfully or unsuccessfully.

It turns out that a perl-style chomp function is really handy!

(defun chomp (str)
  (if (and (stringp str) (string-match "\r?\n$" str))
      (replace-match "" t nil str)
    str))

(defun client-notify-connect (&rest args)
  (message (format "Connection message [%s]" (mapcar #'chomp args))))

I added a fairly hacky (sit-for 1) after opening the client as otherwise I could send messages before it was ready due to the sentinel and nowait. Future versions will probably get the sentinel to set an "opened" variable which will determine whether the send message and close functions work.

(defun client-open (host port)
  (make-network-process :name client-process-name
                        :host host
                        :service port
                        :nowait t
                        :sentinel #'client-notify-connect)
  (sit-for 1))

Closing the connection is a simple matter of deleting the process. I confirmed this against my test perl server.

(defun client-close ()
  (delete-process (client-process)))
(defun client-send-string (str)
  (process-send-string (client-process) (concat str "\r\n")))

My test program simply sends 10 hello messages to the server at the same time as inserting 10 hellos in the buffer. The fact that the buffer insertions completed almost instantaneously whereas the server took around 20 seconds to display the messages indicates there is some degree of separation.

(progn
  (client-open 'local 8080)
  (dotimes (var 10)
    (client-send-string (format "Hello %s" var))
    (insert (format "Hello %s\n" var)))
  (client-close))

Next time I’ll look at setting up a filter to receive messages that the server sends back. Any questions or comments let me know.

If you liked this post, why not subscribe to my RSS feed.

Read Full Post »

A few weeks ago when I was talking about autocomplete and dabbrevone of my commenters asked if I had tried hippie-expand. My response was no, but I should take a look as it might allow me to input buffer names more quickly which is something I often need to do.

Following the recipe from the emacs wiki, I tried this:

(global-set-key [(meta f5)] (make-hippie-expand-function
                             '(try-expand-dabbrev-visible
                               try-expand-dabbrev
                               try-expand-dabbrev-all-buffers
                               try-complete-file-name) t))

After some experimentation, the limitation is obvious. I usually want to complete the entire filename including the path but I can’t remember what the path begins with.

The next thing I thought about was removing *Messages* and *Buffer List* from dabbrev-ignored-buffer-names. Unfortunately, I still need to complete from the beginning of the path but this is generally useful so I’m going to keep it. Really, I want to be able to select any part of the filename and complete from that. Sounds like a job for ido.

First I need a method that returns all buffer names and filenames.

(defun get-files-and-buffers ()
  (let ((res '()))
    (dolist (buffer (buffer-list) res)
      (let ((buffername (buffer-name buffer))
            (filename (buffer-file-name buffer)))
        (unless (string-match "^ *\\*.*\\*$" buffername)
          (push buffername res))
        (when filename (push filename res))))))

Then I can use ido to select between them which is perfect.

(defun insert-file-or-buffer-name (&optional initial)
  (interactive)
  (let ((name (ido-completing-read "File/Buffer Name: "
                                   (get-files-and-buffers)
                                   nil nil initial)))
    (when (and (stringp name) (> (length name) 0))
      (insert name))))

(global-set-key (kbd "<f2> i b") 'insert-file-or-buffer-name)

Read Full Post »

Emacs-fu Emacs Tips

Emacs-fu started a great post requesting little tricks. I gave my own response, covering cut-and-paste, ido mode, uniquify and tidy backups. Da Zhang has a nice summary of some of the other tips.

Using/Extending Core Libraries

There are a few emacs libraries that store current state in global variables. For example, ido stores the list of current matches in ido-matches. Accessing this variable while filtering using ido can be a little convoluted. I gave an example of how to do this in Shell Command on Multiple Buffers.

Dabbrev also uses global variables although it provides [internal] functions for completing an abbreviation. I have a complete example at Autocomplete with a Dabbrev Twist but the core is very simple:

(let ((dabbrev-check-all-buffers t))
  (dabbrev--reset-global-variables)
  (dabbrev--find-all-expansions <abbreviation> t))

Multi-file Search/Replace

I really liked this post from Ian Eure demonstrating how to do multi-file search and replace in emacs. I frequently see emacs proponents saying its awesome and you’ll know when you reach emacs nirvana so it is nice to see a practical demonstration of emacs power. And of course I know it is possible in shell but the simplicity and the interactive nature of emacs makes this a much more pleasant experience. A quick summary:

  • M-x find-grep-dired RET <pattern> (put matching files in dired buffer)
  • m .php$ RET (mark all php files)
  • Q <pattern> RET <replace string> (run query-replace on marked files)
  • C-x s (save all modified files)

Emacs Popularity

So first of all I found this post referring to a thread where a guy says he recommends nano as he has used Unix-like systems that don’t have vi. Hmmm… okay, and then that post has this one from 2007 in the auto-generated links list about Emacs losing in popularity.

And from there I get to this one which has a poll where 56% of the almost 750 respondants chose vim1 as their favourite Linux text editor compared to 9% choosing emacs. Of course it is a highly unscientific result, but do you think more than 6 times as many people use vim as emacs?


1. Fair enough – it is a fine editor

Read Full Post »

So much for good intentions. I get myself all geared up to
the problem I need to solve today? Well, I want to find out about how emacs networking works.

So first, I need a simple server to play with. Now normally when I think server I automatically think Apache but this time I want something a bit more basic. And if I was thinking enterprise1 I might reach for C++/ACE. However, for something basic, Perl is ideal.

I’ve just upgraded to Ubuntu 9.04 on this box and Perl is unused so let’s see if it has what I need.

06.52 Ubuntu finishes booting

I waste a few minutes on the internet.

06.57 I start Emacs

and remind myself just how gorgeous emacs-23 looks.

06.59 I check for the Net::Server package
$ perldoc Net::Server
You need to install the perl-doc package to use this program.
$ sudo apt-get install perl-doc

$ perldoc Net::Server
No documentation found for "Net::Server".

It is not installed. I could install it using apt (it is called libnet-server-perl) but I’ve got in the habit of using Perl’s CPAN module which provides package management facilities too. The advantage is that it is somewhat consistent across platforms.

$ sudo perl -MCPAN -e shell

cpan[1]> install YAML
cpan[2]> install CPAN
cpan[3]> reload CPAN
cpan[4]> install Bundle::CPAN

The CPAN bundle installs quite a bit so I go for breakfast.

07.15 Back from breakfast
cpan[5]> install Net::Server

I took this code pretty much straight from perldoc Net::Server.

#!/usr/bin/perl

use strict;
use warnings;

package SimpleServer;

use base qw(Net::Server);

sub process_request
{
    while (<STDIN>) {
        s/\r?\n$//;
        print STDERR "Received [$_]\n";
        last if /quit/i;
    }
}

SimpleServer->run(port => 8080);

I tested it using telnet localhost 8080 to confirm it does what I need.

07.20 All done

Presumably Python and Ruby have similar incantations that will get a server up and running quickly.

And unfortunately at this point I have to go to work. But later on, I can begin experimenting with emacs networking.


1. i.e. some thing that grows humongous over a period of two years and then no-one wants to work with it anymore.

Read Full Post »

Yes, Emacs is my OS, but I still need to run external programs not written in emacs-lisp from time to time. For example, emacs doesn’t have a method for processing a section of a file – without help from an external program, you need to load the whole thing into a buffer.

Why learn a new programming language?

And no, because the pragmatic programmers told me to learn a new one every year is not a good reason. If it is something you need for work, then the choices is normally straightforward – learn whatever they tell you to learn at your firm.

Languages Used in Industry

If you don’t have a job and want to get one, choose C# if you like Microsoft, Java if you don’t or perhaps PHP if you want to do web programming. C++, Python or Perl might be reasonable choices depending on which industry you want to go into. And no, Python did not "kill" Perl nor did Ruby "kill" Python.

Language Complements

If you already know a systems language such as Java, C# or C++ it is worth learning either Python or Perl. The reverse is a weaker proposition but still true in my opinion. However, if you already know both a systems language and a scripting language, any time invested in learning a new language could be used to improve your knowledge of one of your existing languages – maybe learn a framework such as ACE, Twisted or POE.

Studying For Fun

It may be worth learning a new language if you are just learning for fun and your existing languages don’t cover a particular problem area that you are interested in. For example, if you want to write GUIs and only know C++ and Perl maybe you should learn Python so you can use wxPython (just kidding!).

The problem then is that you can’t do a thorough evaluation of a new language in a small amount time. Perhaps the best you can do is to list features that are important to you and exclude languages on that basis.

So for me, I don’t like to write C++ in my limited spare time and my second language, Perl has a few minor flaws such as threading1. I’m looking for a replacement for pottering about with. My big ticket requirements are:

  • Nothing to do with .NET
  • Portable to at least Linux and Windows
  • I would prefer run-time size to be small for simple program
  • It must have a REPL I can run from Emacs
  • It needs to have fairly complete libraries (which implies)
  • It must have a reasonable size user community
  • Pre-emptive threading would be nice

The JVM Languages

JVM based languages neatly solve the libraries issue and you get threading and portability too. The two languages I would consider here are Clojure and Scala. I’m more interested in the former but I’m a bit concerned about run-time size. From what people tell me, three or four Java clients is all a decent PC can take before it falls over.

D, Haskell, Ocaml

I suspect all of these make relatively small runtimes. Haskell immediately excludes itself as any language where I can’t put a Printf where I want sucksis not the language for me.

Scheme / Common Lisp

There are simply too many scheme implementations which must affect the size of the user community so I’m ruling scheme out. And if I’m going to run a Common Lisp VM, why not use Clojure instead and get the Java Libraries for free?

Lua

Lua covers most of the points. I just need to check if it has a REPL.

So following that set of (weak) justifications, my shortlist consists of Clojure, Ocaml, Lua and Perl of course. Next I’m going to do a very basic check of runtime size.


1. Since discovering POE, I haven’t needed threads so perhaps I should admit that whenever raw speed is unimportant (and that is usually the case) Perl might be my perfect language.

Read Full Post »

Older Posts »

Follow

Get every new post delivered to your Inbox.