Table of Contents

Introduction

This website is intended to be a useful resource for people, who are interested in the history of the popular programming language Haskell. It is far away from being complete, i.e. any suggestions are greatly welcome. At this point we would like to thank the following persons for their important and immediate help:
  • Björn Lisper: template as regards the content
  • Arjan van IJzendoorn: layout of this website
  • Stefan Wagenbrenner
  • Fritz Ruehr: the beautiful logo
To do (help is appreciated):
  • include old releases of well known Haskell compilers and interpreters
  • more links to other resources in the web
  • providing a more detailed history

Top

Theoretical roots

"Lambda calculus is a formal language capable of expressing arbitrary computable functions. In combination with types it forms a compact way to denote on the one hand functional programs and on the other hand mathematical proofs." (Barendregt)

This statement puts across the relation of functional programming and Lambda Calculus in a nutshell. Originally it was conceived by Church in 1932 intended to be a foundation for mathematics. At first sight it is hard to imagine that such an extremely simple formal language of functions suffices to compute everything which is computable at all. But indeed, the Lambda Calculus is a successful model for the computable functions (proven by Kleene and Rosser 1936) and hence equivalent to popular approaches like the Turing machine (proven 1937 by Turing). By the way, there were other famous mathematicians, too, which developed parts of this powerful theory: We want and have to mention Schönfinkel and Haskell Curry, the godfather of the programming language Haskell (see a biography), who defined a variation called combinatory logic. Of course these early logicians had no intention to define any programming languages (maybe because the lack of computers).

The theory of lambda-definable functions provides some extremely important results for functional programming, which we have to mention at this point:

  • There are appropriate lambda terms even for recursively defined functions. The fixed point theorem guarantees for every lambda term f a lambda term x such that x = f x (the theorem provides an easy way to get this x using the fixed point combinator Y).
    Example: mult = (\f x y->if x==0 then 0 else y + f (x-1) y) mult
  • From the Church-Rosser theorem it follows that a term has at most one normal form (so results of Haskell functions/programs are not ambiguous). Furthermore reduction can not enter dead-end streets. If there is a normalform it is never to late to find it. Nevertheless, the reduction strategy is responsible for efficiency and termination.
  • The call by name reduction-strategy is normalizing, i.e. if there is a normal form call by name will time. The problem: one has to take care for the avoidance of multiple evaluation of the same expression (call by value is not normalizing, but this problem can not arise).
  • It is possible to assign types to lambda terms. Established well known algorithms are both complete and sound. There are two different approaches: explicit typing (Church), which means, that every subexpression has to be annotated with its type, and implicit typing (Curry), the Haskell way of typing (the typechecker computes the types automatically if the particular expression is typable at all).

Further (and far more technical) information about the Lambda Calculus can be found e.g. in the papers of Barendregt (Lambda Calculi with Types, 1992).

Top

Some historical and up to date functional languages

We start our exploration with a citation of the introduction of Hudak's "Conception, Evolution, and Application of Functional Programming Languages":

"The first programming languages were developed with one simple goal in mind: to provide a vehicle through which one could control the behavior of computers. Not surprisingly, the early languages reflected the structure of the underlying machines fairly well."
But this conception became obsolete quickly, because of the following reasons:
  • bad maintainability (have you ever tried to understand an existing assembler program a fairly long time later?)
  • very low level of abstraction (consequence: bad portability)
Hence the need for a common language arose with which all machines could be programmed independently. Imperative programming languages were a first improvement and the basic approach was to program a sequence of commands which change some state of the machine. Note, that this is not that far away from assembler. Their major innovation was the provision of higher-level commands, e.g. printf instead of storing certain bits in graphic memory. C and Ada are important examples of this programming paradigm. Both are widely used, e.g. C for the implementation of operating systems and Ada in real-time systems. Another approach is given by object-oriented programming languages for instance Java or C++. They implement a lot of the principles of modern software engineering, e.g. ease of extensibility of existing programs (classes) and modularization. There are a lot of interesting design patterns, but something is missing: expressiveness (people which have ever seen a Java program will understand this immediately). At this point functional programming languages appear, which focus to the evaluation of expressions, i.e. the underlying model of computation is the function (in contrast, the relations play an important role in logical programming). They provide an easy way of implementing algorithms as close to the problem as possible. Furthermore, most of them (especially Haskell) are typed more strongly than Java avoiding mistakes which creep in the programs subversively (e.g. triggered by wrong casts). All of these concepts can be read in the Haskell 98 report or other related work and will not be the root of the matter in this article further on.

The first functional programming language (which is still alive and widely used, consider e.g. emacs or sawfish) has been LISP, which was invented and defined by McCarthy in 1960. It has been very successful mainly because of its extensibility (see Steele: Growing a Language). In fact, in LISP, user-defined functions look like primitives and hence there was a great deal of stimulation to extend the language. So there have been many dialects over the years, e.g. Common Lisp and Scheme. LISP has been (and is) widely used in areas like AI, and as a macro language on top of software. Note, that LISP's recipe for success is also one of the basic principles of Haskell, too. APL was also an early programming language suited to describe mathematical ideas and with powerful mechanisms for the manipulation of arrays.

We apologize that the following part is copied and only slightly adapted from Björn Lisper presently, but in the near future it will hopefully evolve to an independent review of the interesting history of Haskell.

In the late 70's, Backus put forward the idea of a "pure", higher order programming language with syntax similar to combinatory logic. He defined the language FP, which has been very influential for the further development of functional languages. An important idea in FP is that of higher order functions, i.e., functions that take functions as arguments or return them as results.

At about the same time, researchers at the University of Edinburgh who dealt with automatic theorem proving found they needed a language to express strategies for proof search. They defined the language ML ("Meta-Language") for this purpose. Soon, they found out that ML actually could serve as a powerful general programming language, and it developed into such. Besides being higher-order like FP (but richer in syntax), it hosts important features like type inference, i.e., the ability to infer types for all parts of the program without there being any explicit type declarations. Many features of Haskell originate in ML, and the languages have quite similar "look-and-feel". Like Lisp there have been many dialects of ML. It is still a widely used functional language, which is often used as language in basic courses on functional programming. Two important and well known dialects of ML are Standard ML of New Jersey (SML) and CAML.

Another ML-like language is Miranda, developed in 1985-1986. It is one of the first lazy, or non-strict functional languages. Such languages try to defer evaluation of expressions until the result is needed. This gives a different semantic to the language than if "eager" evaluation is used, and makes it possible to use features such as potentially infinite data structures. The Haskell committee originally wanted to use Miranda as a starting point, but the designer and owner of Miranda was not interested.

The functional language that is probably being most used in industry is Erlang, a functional language with concurrent processes. Erlang was developed at Ericsson primarily for telecom applications, but it is a general programming language. Erlang has been around since the late eighties.

Functional languages have also been developed for scientific computing applications. The main reason to use functional languages for this class of application is the very straightforward parallelization of functional programs, which was hoped to outweigh the loss of efficiency that functional program often experience from their more costly evaluation mechanisms and memory requirements. Two prominent representatives for this class of languages are Sisal and Id Nouveau.

Some links suggested by interested readers

Top

The introduction of Haskell

This variety of functional programming languages led to some confusion and although each one has its specific features and advantages the need for a standard emerged. At the end of this process a brand-new programming language arose: Haskell.

Haskell was an attempt to create "the" standard, non-strict, higher order functional language to achieve a consistent base for research (e.g. by providing uniform identifiers for common functions). It contains many of the features from earlier functional languages, such as higher order functions, type inference, and non-strict semantics. A novel invention in Haskell is type classes, a structured form of overloading that is reminiscent of how method names are overloaded in object-oriented languages. The first version of Haskell (1.0) was defined in 1990.

The following can be read in the preface of the Haskell 98 Report:

"Haskell has indeed evolved continuously since its original publication. By the middle of 1997, there had been four iterations of the language design (the latest at that point being Haskell 1.4). At the 1997 Haskell Workshop in Amsterdam, it was decided that a stable variant of Haskell was needed; this stable language is the subject of this Report, and is called Haskell 98."

Top

Perspectives of Haskell

Top

Links, related work

Haskell Archives

In this section we want to provide a collection of links pointing to archives of well known Haskell-related software, e.g. compilers and interpreters. We think, that it is really interesting and important, to have a look at their genesis (in almost the same manner we can learn from our history), to avoid mistakes that have already be done before. Software like the GHC or Hugs have been grown for many years. It is really characteristical for computer sciences that ideas are reused (even if they seem to be obsolete, they often will be revitalized in the future). And hence quick access to history-related stuff should be provided.

GHC

The Glasgow Haskell Compiler is well known and widely used.

NHC

The nhc is a popular Haskell compiler, too. It was first written in 1993/94, so there is nothing available earlier than Haskell 1.2. The nhc never supported Haskell 1.4, but jumped directly to Haskell'98 instead.

Top

Send comments to Steffen Mazanek,
steffen.mazanek@unibw-muenchen.de, www.steffen-mazanek.de
Haskell: that's where I just curry until fail, unwords any error, drop all undefined, maybe break, otherwise in sequence span isControl and take max $, id: (d:[])