We are now ready to draw some comparisons between ML and Haskell.
ML is a statically scoped, programming language that supports primarily functional programming with a safe type system, type inference, an eager evaluation strategy, parametric polymorphism, algebraic data types, pattern matching, automatic memory management through garbage collection, a rich and expressive polymorphic type and module system, and some imperative features. ML integrates functional features from Lisp, rule-based programming (i.e., pattern matching) from Prolog, data abstraction from Smalltalk, and has a more readable syntax than Lisp. As a result, ML is a useful general-purpose programming language.
Haskell is a fully curried, statically scoped, (nearly) pure functional programming language with a lazy evaluation parameter-passing strategy, safe type system, type inference, parametric polymorphism, algebraic data types, pattern matching, automatic memory management through garbage collection, and a rich and expressive polymorphic type and class system.
Table 9.7 compares the main concepts and features of ML and Haskell. The primary difference between these two languages is that ML uses eager evaluation (i.e., call-by-value) while Haskell uses lazy evaluation (i.e., call-by-name). Eager evaluation means that all subexpressions are always evaluated. These parameter-passing evaluation strategies are discussed in Chapter 12. Unlike Haskell, not all built-in functions in ML are curried. However, the higher-order functions map, foldl, and foldr, which are useful in creating new functions, are curried in ML. ML and Haskell share a similar syntax, though the syntax in Haskell is terser than that in ML. The other differences mentioned in Table 9.7 are mostly syntactic. Haskell is also (nearly) purely functional, in that it has no imperative features or provisions for side effects, even for I/O. Haskell uses the mathematical notion of a monad for conducting I/O while remaining faithful to functional purity. The following expressions succinctly summarize ML and Haskell in relation to each other and to Lisp:
Table 9.7 Comparison of the Main Concepts and Features of ML and Haskell
Concept | ML | Haskell |
---|---|---|
lists | homogeneous | homogeneous |
cons | :: | : |
append | @ | ++ |
integer equality | = | == |
integer inequality | <> | /= |
strings | not a list of characters use explode | a list of Characters |
renaming parameters | lst as (X::XS) | lst@(X:XS) |
functional redefinition | permitted | not permitted |
pattern-directed invocation | yes, with | | yes |
parameter passing | call-by-value, | call-by-need, |
functional composition | o | . |
infix to prefix | (op operator) | (operator) |
sections | not supported | supported, use (operator) |
prefix to infix |
| ‘operator‘ |
user-defined functions | introduced with fun can be defined at the prompt or in a script | must be defined in a script |
anonymous functions | (fn tuple => body) | ( tuple -> body) |
curried form | omit parentheses, commas | omit parentheses, commas |
curried | partially | fully |
type declaration | : | :: |
type definition | type | type |
data type definition | datatype | data |
type variables | prefaced with ’ written before data type name | not prefaced with ’ written after data type name |
function type | optional, but if used, embedded within function definition | optional, but if used, precedes function definition |
type inference/checking | Hindley-Milner | Hindley-Milner |
function overloading | not supported | supported through qualified types and type classes |
ADTs | module system (structures, signatures, and functors) | class system |
The features of ML are ideally applied in language-processing systems, including compilers and theorem provers (Appel 2004). Haskell is also being increasingly used for application development in a commercial setting. Examples of applications developed in Haskell include a revision control system and a window manager for the X Window System. Galois is a software development and computer science research company that has used Haskell in multiple projects.6
ML and Haskell are also used for artificial intelligence (AI) applications. Traditionally, Prolog, which is presented in Chapter 14, has been recognized as a language for AI, particularly because it has a built-in theorem-proving algorithm called resolution and implements the associated techniques of unification and backtracking, which make resolution practical in a computer system. As a result, the semantics of Prolog are more complex than those of languages such as Scheme, C, and Java. A Prolog program consists of a set of facts and rules. An ML or Haskell program involving a series of function definitions using pattern-directed invocation has much the same appearance. (The built-in list data structures in Prolog and ML/Haskell are nearly identical.) Moreover, the pattern-directed invocation built into ML and Haskell is similar to the rule system in Prolog, albeit without the semantic complexity associated with unification and backtracking in Prolog.
However, ML and Haskell, unlike Prolog, include currying and curried functions and a powerful type and module system for creating abstract data types. As a result, ML and Haskell are used for AI in applications where Prolog (or Lisp) might have been the only programming language considered in the past. Curry, nearly a superset of Haskell, is an experimental programming language that seeks to marry the functional and logic programming in a single language. Similarly, miniKanren is a family of languages for relational programming. ML (and Prolog) were developed in the early 1970s; Haskell was developed in the early 1990s.
Some beginner programmers find the constraints of the safe type system in ML and Haskell to be a source of frustration. Moreover, some find type classes to be a source of frustration in Haskell. However, once these concepts are understood properly, advanced ML and Haskell programmers appreciate the safe, algebraic type systems in ML and Haskell.
The subtle syntax and sophisticated type system of Haskell are a double edged sword—highly appreciated by experienced programmers but also a source of frustration among beginners, since the generality of Haskell often leads to cryptic error messages. (Heeren, Leijen, and van IJzendoorn 2003, p. 62)
An understanding of the branch of mathematics known as category theory is helpful for mastering the safe, algebraic type systems in ML and Haskell. Paul Graham (n.d.) has written:
Most hackers I know have been disappointed by the ML family. Languages with static typing would be more suitable if programs were something you thought of in advance, and then merely translated into code. But that’s not how programs get written. The inability to have lists of mixed types is a particularly crippling restriction. It gets in the way of exploratory programming (it’s convenient early on to represent everything as lists), . . . .
18.191.189.23