[Shootout-list] dispatch
Jon Harrop
jon at ffconsultancy.com
Fri Jul 29 05:14:23 UTC 2005
I've just written a few OCaml implementations of the dispatch test. This is
another test which computes a trivially reducible expression (the answer is
450N) and, unsurprisingly, a line must be drawn completely arbitrary to
determine which implementations are and are not allowed, i.e. "print(450*n)"
is probably not allowed.
The following implementation uses:
1. A functional style (rather than the original imperative style).
2. Static typing via modules and functors rather than dynamically-typed
objects.
3. Variant types instead of inheritance hierarchies (the same as my ray
tracer).
At about 55LOC, the resulting program is much shorter than all other
implementations and is probably faster. It can be argued that this is a valid
and interesting submission on the basis that it uses static typing to evade
run-time type tests.
This test can be written in many different ways in OCaml. Potentially, all are
interesting. For example:
1. Objects can be used either imperatively or functionally.
2. HOFs can be used to replace the functor.
3. Records of functions can be used to replace objects/modules.
Anyway, here's the code:
module BottleState = struct
type t = Empty | Full | Sealed
let initial = Empty
let next = function Empty -> Full | Full -> Sealed | Sealed -> Empty
let tag = function Empty -> 1 | Full -> 2 | Sealed -> 3
end
module PressurizedBottleState = struct
type t = Empty | Full | Unsealed | Sealed
let initial = Empty
let next = function
Empty -> Full | Full -> Unsealed | Unsealed -> Sealed | Sealed -> Empty
let tag = function Empty -> 4 | Full -> 5 | Unsealed -> 6 | Sealed -> 7
end
module Make = functor (State : sig
type t
val initial : t
val next : t -> t
val tag : t -> int
end) -> struct
type t = { state: State.t; id: int }
let initial_state = State.initial
let empty b = { b with state = State.next b.state }
let fill b = { b with state = State.next b.state }
let seal b = { b with state = State.next b.state }
let cycle b = empty (seal (fill b))
let check b c = State.tag b.state + b.id + c
let make id = { state = State.initial; id = id }
let bottle_check b1 b2 b3 b4 b5 i =
let c = i mod 2 in
check (cycle b1) c + check (cycle b2) c + check (cycle b3) c +
check (cycle b4) c + check (cycle b5) c
end
module Bottle = Make(BottleState)
module PressurizedBottle = struct
include (Make(PressurizedBottleState))
let pressurize b = { b with state = PressurizedBottleState.next b.state }
let cycle b = empty (seal (pressurize (fill b)))
end
let () =
let n = int_of_string Sys.argv.(1) in
let [b0;b1;b2;b3;b4;b5;b6;b7;b8;b9] =
List.map Bottle.make [0;1;2;3;4;5;6;7;8;9] in
let [p0;p1;p2;p3;p4;p5;p6;p7;p8;p9] =
List.map PressurizedBottle.make [0;1;2;3;4;5;6;7;8;9] in
let check = ref 0 in
for i=1 to n do
check := !check + Bottle.bottle_check b1 b2 b3 b4 b5 i;
check := !check + Bottle.bottle_check b6 b7 b8 b9 b0 i;
check := !check + PressurizedBottle.bottle_check p1 p2 p3 p4 p5 i;
check := !check - PressurizedBottle.bottle_check p6 p7 p8 p9 p0 i;
done;
print_endline (string_of_int !check)
--
Dr Jon D Harrop, Flying Frog Consultancy Ltd.
Objective CAML for Scientists
http://www.ffconsultancy.com/products/ocaml_for_scientists
More information about the Shootout-list
mailing list