[clue-talk] Stupid OCaml tricks
Matt Gushee
matt at gushee.net
Mon Aug 14 12:55:22 MDT 2006
Hey ho.
During my presentation last week, Dennis asked something along the lines
of "what makes OCaml a better language for you?" Can't recall the exact
words, but I believe that was the gist of it. I don't think I answered
the question very well, so let me give y'all an example that might give
you a better idea.
In reading this, consider the notion of programming *idioms*. After all,
in terms of fundamental capabilities, most languages are pretty
interchangeable. But the idioms that they support can have a huge effect
on whether a given language is comfortable and productive for you. OCaml
supports a number of idioms that work well for me.
The following is a simplified version of a technique I thought of a
couple of days ago (the first time in history anyone's thought of
something like this, I'm sure ;-)). I think that this kind of thing can
only be done elegantly in an impure functional language like OCaml. You
could do something similar in Python, but it wouldn't be type-safe.
PROBLEM:
An image viewer has several modes of operation: fullscreen vs. not,
slideshow vs. manual, etc. The user is allowed to switch between
modes at runtime. Each time an image is displayed, it needs to be
displayed in an appropriate manner for the current mode.
CONVENTIONAL SOLUTION:
Set up some flags to indicate the mode, and test them each time
an image is displayed:
let mode = {
fullscreen = false;
slideshow = false;
interval = 1000; (* milliseconds *)
}
....
let show_image img =
if mode.slideshow && mode.fullscreen then
[ do something ]
else if mode.slideshow then
[ do something else ]
else if mode.fullscreen then
[ something else again ]
else
[ etc. ]
WHAT'S WRONG WITH THAT?
1. Evaluating conditionals can affect performance (honestly, the
effect is probably minuscule in this case, but it's not zero, and
might be large in some cases).
2. There is no clear mechanism for managing the mode, making bugs
more likely and debugging harder.
So-o-o:
WAY-COOL, IMPURE FUNCTIONAL SOLUTION
1. Create a type to represent mode transitions (this part is
optional, but contributes to the clarity of your code):
type transition =
| FullscreenOn
| FullscreenOff
| SlideshowOn
| SlideshowOff
These symbols will be generated in response to keyboard or mouse
events.
2. Create the show_image function as a reference:
let show_image = ref (fun img -> ())
OCaml uses '()' for the value called 'unit', which is more or
less like void in C. Since a function has to return a value,
you use () when there is no interesting value to return. So the
above function is a no-op. The 'ref' keyword means the value is
a *reference* (similar to a 'pointer' in some other languages).
Unlike normal variables in OCaml, references are mutable and can
be assigned values.
3. Create a "function factory" that returns a mode-specific
function:
let get_show_image mode =
match mode.slideshow, mode.fullscreen with
| true, true -> (fun img -> [ do something ])
| true, false -> (fun img -> [ do something else ])
| false, true -> (fun img -> [ something else again ])
| false, false -> (fun img -> [ etc. ])
So, depending on the current mode, the above function returns
one or another *function* that does something with an image.
4. Create a set_mode function that manages transitions:
let set_mode transition =
(* I'm not showing the transform_mode function, but the
concept is self-explanatory, I hope. *)
let new_mode = transform_mode current_mode transition in
show_image := get_show_image new_mode
(* ':=' is how you assign to a reference *)
5. How to display an image:
!show_image img
(* '!' is used to dereference the reference, whose current
value has been set by the 'set_mode' function *)
So, what have we done? Well, now, instead of checking the mode every
time we display an image, we check it *only* when it changes, and swap
out our main display function accordingly. And when !show_image is
called, it just does its thing with little or no evaluation of
conditionals. Furthermore, there is only one function that can change
the mode, so in addition to a possibly-tiny performance boost, we also
gain a significant amount of clarity in how the program functions: if
the current state is X, the current display function *must be x*. So
when you need to debug, the logic looks something like this:
1. Does the mode get changed appropriately?
NO: fix the set_mode function.
YES: go to (2).
2. Is the show_image function for this mode correct?
NO: fix it
YES: Umm ... well, you get the idea.
I think that's pretty damn cool. No doubt it is overly elaborate for
some situations. I think the distinction between "scripting languages"
and "programming languages" is somewhat bogus, but to the extent that
it's valid, OCaml is definitely the latter. So, right tool for the right
job: if I needed a quick system administration script, I'd look at
(e.g.) Python first, but for a moderately-to-highly complex desktop
application, OCaml would be my first choice.
--
Matt Gushee
: Bantam - lightweight file manager : matt.gushee.net/software/bantam/ :
: RASCL's A Simple Configuration Language : matt.gushee.net/rascl/ :
More information about the clue-talk
mailing list