cgibbard's comments

cgibbard | 12 years ago | on: Programming With Types, Not Tutorials

The library described in the article gives you a way to take an arbitrary data type, and treat its values as the primitive actions of an embedded domain-specific language (that's what singleton does), and then write interpreters for that language by saying how those primitives should be interpreted (which is what interpret does). All (or at least most of) the control structures for the language come for free, because there's an instance of Monad.

This tends to be quite helpful especially in the case where there are multiple interpretations you might be interested in. For example, a graphics library might provide an interpreter that executes drawing primitives using OpenGL to put stuff on the screen directly, as well as one which interprets the same data by manipulating arrays of pixels. Perhaps another could construct an SVG.

To do that, you'd provide a data type whose constructors would encode whatever drawing primitives your library supported, things like circles and lines and Bézier splines, and then use the interpret function to define each interpreter by supplying a function which takes a given primitive and says how to carry out whatever actions are needed to be taken to display or render it.

(Note: this example is likely a little simplistic, because most of the operations in a drawing library won't have return values, but this set-up allows for such things. You could also make a version where the things drawn also continuously produce values by reacting to user input, allowing for some sort of optional interactivity.)

You'd also likely define a bunch of user-facing versions of the primitives which would amount to singleton applied to each of the constructors of your data type, just for the sake of convenience and implementation-hiding.

Then you have a library where people can define complex drawings in terms of the primitives you provided, and supply any one of those to any one of the interpreters you defined in order to put it on the screen, or write it out to an SVG file, or whatever.

For no additional work, you get operations like

sequence :: [Drawing a] -> Drawing [a]

from the monad library, for taking a list of drawings and producing a drawing which carries them out in sequence (whatever you've decided that ought to mean via your interpretations, probably stacking them on top of each other), as well as many others.

A more interesting example (in that it would involve input as well as output) might be a library for coordinated communication of some sort over different types of underlying network protocols (necessitating different interpreters for the primitive communication operations). Again, you'd get lots of control structures for free, things like for-each loops, and ways to define new bits of a protocol by applying a function to the results of a bunch of smaller pieces of communication.

page 1