Reviving the Gofer Standard Prelude (circa. 1994)

Gofer (“GOod For Equational Reasoning”) was an early implementation of a Haskell 1.x-ish language by Mark Jones, originally released in 1991 (and written as a secret side project by Mark). It was famously used to develop type classes, do-notation and useful libraries involving them. It supported numerous interesting extensions (constructor classes , m*n+k patterns…). By 1994, it was rewritten to match the Haskell standard at the time, resulting in Hugs. Gofer was the first Haskell system I used (I used MacGofer, on a 68k Macintosh, to implement my comp1A assignments, including a CGI maze solving game with AI).

Gofer also supported easy addition of custom preludes, and comes with a number of interesting ones. I’ve started packaging up these prelude experiments with Cabal, and you can now get the gofer standard prelude from Hackage. The minimal prelude, constructor classes prelude, nofloat prelude, and the simplified preludes are still to come.

One major difference is the entire absence of monads of any kind. Instead, to remain referentially transparent in IO, the gofer standard prelude used continuation-based IO (the successor to the very early stream-based IO model of Miranda).

Programs are represented as functions of the type:

type Dialogue = [Response] -> [Request]

where Responses are values from the operating system, that are returned when the program makes requests of the kernel. The different kinds of requests we can make using the Gofer standard prelude:

are defined to be strict, tail recursive loops. (These days we use the lazy foldl, and rely on rewrite rules to transform strict Num types into foldl’ – not an entirely satisfactory situation). These would be better definitions.

Interestingly, Gofer exported very few data types, with only Int and Float available by default (no Integer). The port of the gofer prelude to GHC reuses GHC’s implementations of these data types, and other primitives on them, as well as reimplementing strict and error in terms of GHC’s seq and error.

In addition, to write a new Prelude in GHC, you have to disable the old one, with -XNoImplicitPrelude which turns off all the Prelude types , and makes the syntax for enumerations, list comprehensions, do-notation, arrows and numeric literals rebindable.

These syntactic features desugar to various functions (fromRational, fromInteger, fail, (>>), (>>=)), so we have to ensure the Gofer versions of these functions are in scope instead.

Gofer was also my gateway drug leading to Haskell addiction. And you examples bring up some good old memories. In school we had an assignment to write a hangman program in Gofer using the continuation-based IO. I remember it as being quite painful. I’m glad it didn’t scare me away though. Not long after I found a tutorial on monadic IO which was some very welcome news.

It’s funny how the Gofer prelude still has its place somewhere in the back of my head. Even to this day I sometimes look for functions like sum, product and copy in the Haskell Prelude only to find that they aren’t there.

That makes sense, although then I think strict in Hugs would be the same as $! in Haskell. This doesn’t match the description of strict that you give since the argument is forced, not the result of the evaluation of the function.