Ackermann's Function in Scheme

      (import (scheme base)
              (rnrs arithmetic fixnums)
              (scheme write)
              (scheme process-context)
              (scheme time)
              (scheme inexact))
      
      (define (ack m n)
        (cond ((fx=? m 0)
               (fx+ n 1))
              ((fx=? n 0)
               (ack (fx- m 1) 1))
              (else
               (ack (fx- m 1)
                    (ack m (fx- n 1))))))
      
      (define args (command-line))
      
      (define (go)
        (let ((m (string->number (list-ref args 1)))
              (n (string->number (list-ref args 2))))
          (if (and (fixnum? m)
                   (fixnum? n))
              (let* ((t0 (current-jiffy))
      	              (result (ack m n))
                     (t1 (current-jiffy)))
                (write (inexact (/ (- t1 t0) (jiffies-per-second))))
                (display " seconds to compute (ack ")
                (write m)
                (display " ")
                (write n)
                (display ")\n")
                (write result)
                (newline)))))
      
      (go)
    

The fairness of that translation might be a little controversial because:

Using fixnum arithmetic might be fair because C and Java aren't using generic arithmetic.

Excluding compilation time might be fair because we're going to exclude compilation time for C and Java when we run the benchmarks.

Excluding the time needed to load libraries might be fair because the C version links the needed libraries into an executable ahead of time.

When we time the Java version, however, we won't link the libraries into an executable ahead of time. If you use inputs that make this benchmark run for only a few seconds, that will be unfair to Java. With this particular benchmark, however, using inputs that would make the Java version run for more than a few seconds would generate a stack overflow, which might look worse than a slow running time. What's fair?

For debugging: Click here to validate.