1 History
1.1 Early development and the Haskell Committee
Haskell originated in 1987 when a committee of researchers convened to consolidate existing lazy functional languages. The Haskell Committee, formed at the Functional Programming Languages and Computer Architecture (FPCA) conference, aimed to design a single, open standard that combined the best features of languages such as Miranda, Orwell, and Lazy ML. The first version of the language specification was published in 1990, named after logician Haskell Curry. The committee continued to refine the language, producing revised reports in 1992 and 1996.
1.2 Haskell 98 standard
Haskell 98, released in 1998, was the first stable and widely adopted version of the language. It aimed to provide a minimal, portable core suitable for teaching, research, and practical programming. The Haskell 98 Report defined the language syntax, semantics, and a standard library. This version became the foundation for textbooks, courses, and the initial growth of the Haskell ecosystem.
1.3 Haskell 2010 and beyond
The Haskell 2010 standard introduced incremental improvements, including the Foreign Function Interface (FFI), bang patterns, and the default language extension mechanism. Subsequent development has been driven by the Glasgow Haskell Compiler (GHC) and a series of language extensions defined through the Haskell Prime process. While no new full language standard has been published since 2010, GHC's "Haskell" effectively encompasses a large set of extensions that have become de facto language features.
2 Language features
2.1 Pure functions and referential transparency
Haskell is a purely functional language: functions have no side effects, and a function called with the same arguments always returns the same result. This property, known as referential transparency, allows code to be reasoned about mathematically, simplifies testing, and enables aggressive compiler optimizations. All computations are expressed as evaluations of expressions, with no mutable state or implicit modifications.
2.2 Lazy evaluation
Haskell employs lazy (non-strict) evaluation by default. Expressions are not evaluated until their results are required, which enables the definition of infinite data structures, modular program design, and the separation of control flow from data generation. Lazy evaluation can improve efficiency by avoiding unnecessary computations, but it also introduces potential space leaks and complicates reasoning about performance.
2.3 Type system
2.3.1 Hindley-Milner type inference
Haskell's type system is based on the Hindley-Milner type inference algorithm. The compiler can automatically deduce the types of most expressions without explicit annotations, making code concise while preserving type safety. In practice, programmers often write type signatures for top-level functions as documentation, but inference handles local bindings and complex nested expressions.
2.3.2 Type classes and ad-hoc polymorphism
Type classes provide a mechanism for ad-hoc polymorphism, allowing functions to operate on multiple types that share a common interface. A type class defines a set of operations (methods); any type can be made an instance of that class by providing implementations. For example, the Eq class defines equality, and Num defines numeric operations. Type classes support overloading in a principled way, distinguishing them from generic functions in other languages.
2.3.3 Higher-kinded types
Haskell’s type system supports higher-kinded types, which are types that take other types as parameters. For instance, the Maybe type constructor has kind * -> *, meaning it expects a concrete type to produce a concrete type. This allows the definition of generic abstractions like Functor, Applicative, and Monad that can work across a wide range of container or effect types.
2.4 Monads
2.4.1 The IO monad
Monads in Haskell provide a structured way to sequence computations that involve side effects, such as input/output, mutable state, or exceptions. The IO monad encapsulates operations that interact with the outside world, ensuring that referential transparency is preserved for pure functions. Programs are structured as compositions of monadic actions, and the entry point (main) is an IO action.
2.4.2 State, Reader, and Writer monads
Other common monads model specific computational patterns: State threads a mutable state through a sequence of operations; Reader provides a read-only environment; Writer accumulates output (e.g., logs) alongside a result. These monads allow pure functions to simulate imperative-style programming while retaining the benefits of purity and composability.
2.4.3 Monad transformers
Monad transformers enable the combination of multiple monadic effects. For example, StateT on top of IO yields a computation that can both maintain state and perform input/output. Haskell’s transformers and mtl libraries provide standard transformers and type classes that allow stacking and interleaving effects in a modular way.
2.5 Algebraic data types and pattern matching
| Algebraic data types (ADTs) allow the definition of composite types via sum (choice) and product (combination) constructs. For example, `data Shape = Circle Float | Rectangle Float Float` defines a type that can be either a circle or a rectangle. Pattern matching deconstructs values of ADTs, enabling concise and expressive case analysis. GADTs (Generalized Algebraic Data Types) extend this with more precise type constraints. |
|---|
2.6 List comprehensions and do notation
| List comprehensions provide a concise syntax for generating lists based on existing lists, using generators and guards. For example, `[x*2 | x <- [1..10], odd x]` yields the doubles of odd numbers from 1 to 10. Do notation, originally introduced for monads, offers an imperative-looking way to sequence monadic actions, improving readability for complex effectful code. |
|---|
3 Programming paradigms and idioms
3.1 Functional reactive programming
Functional Reactive Programming (FRP) models time-varying values and events as first-class citizens. Libraries like Reflex, Yampa, and Rhine allow Haskell programmers to build interactive systems (GUIs, games, robotics) using declarative, compositional abstractions. FRP in Haskell emphasizes the separation of continuous behaviors from discrete events.
3.2 Lenses and optics
Lenses and optics provide composable means to focus on parts of nested data structures. A lens combines a getter and a setter for a specific field; prisms, traversals, and isomorphisms extend the concept to sum types and other patterns. The lens library is famous for its expressive power and is widely used in Haskell projects for data access and modification.
3.3 Effects and effect systems
Haskell’s ecosystem explores advanced effect systems that go beyond monad transformers. Libraries like free and freer-simple model effects as algebraic operations, while polysemy and eff offer efficient, flexible effect handlers. Effect systems allow programmers to declare and compose effects in a type-safe manner, with the goal of achieving better modularity and separation of concerns.
4 Tooling and ecosystem
4.1 Glasgow Haskell Compiler (GHC)
GHC is the most widely used Haskell compiler, known for its powerful optimization passes, support for numerous language extensions, and interactive environment GHCi. It compiles Haskell to native machine code or to portable bytecode via LLVM. GHC also includes a profiler, a debugger, and tools like haddock for documentation generation.
4.2 Build systems: Cabal and Stack
Cabal is the standard build system for Haskell packages, managing dependencies, compilation, and testing. Stack is an alternative build tool that provides deterministic builds by locking package versions via Stackage snapshots. Both tools integrate with Hackage and support multi-package projects, enabling reproducible builds for production environments.
4.3 Package repositories: Hackage and Stackage
Hackage is the central community-operated repository of Haskell packages, where authors publish libraries and applications. Stackage is a curated subset of Hackage packages that have been tested for compatibility with a specific GHC version. Stackage snapshots provide stable, dependency-resolved sets of packages, simplifying project setup.
4.4 Testing frameworks: QuickCheck and HSpec
QuickCheck pioneered property-based testing: programmers specify properties that should hold for all inputs (e.g., reverse (reverse xs) == xs), and the framework generates random test cases to falsify them. HSpec is a behavior-driven development (BDD) testing framework inspired by RSpec; it provides a concise syntax for describing and verifying program behavior. Both are widely used in the Haskell community.
5 Notable applications and libraries
5.1 Web frameworks: Yesod and Servant
Yesod is a robust, type-safe web framework that uses Template Haskell and persistent libraries to ensure compile-time validation of URLs, forms, and database queries. Servant offers a more declarative approach, defining APIs as type-level specifications from which client and server code are automatically generated. Both frameworks emphasize safety and maintainability.
5.2 Data analysis and machine learning
Haskell libraries such as hmatrix, accelerate, and tensorflow/hasktorch enable numerical computing, GPU programming, and deep learning. The statistics and mwc-random packages support statistical analysis. These tools are used in research and increasingly in industrial data pipelines where correctness and expressiveness are valued.
5.3 Concurrency and parallelism
Haskell’s pure, side-effect-free core facilitates safe concurrent and parallel programming. The Control.Concurrent module provides lightweight threads and software transactional memory (STM). Libraries like async simplify structured concurrency, while par and Strategies enable parallel evaluation of pure computations. GHC’s runtime supports multi-core execution with a work-stealing scheduler.
5.4 Financial modeling
Haskell has been adopted by several financial institutions for modeling derivatives, risk analysis, and quantitative trading. Companies like Standard Chartered and Galois have used Haskell for its strong type safety, which helps prevent costly errors in financial computations. The language’s expressiveness allows domain experts to implement complex mathematical models with high confidence.
6 Related languages and influences
6.1 ML and OCaml
Haskell shares many ideas with the ML family—particularly static typing, type inference, and pattern matching on algebraic data types. However, Haskell is distinguished by its strict commitment to purity and lazy evaluation, whereas ML languages (Standard ML, OCaml) embrace impure features (references, loops) and eager evaluation. OCaml’s object system and industrial focus contrast with Haskell’s academic roots.
6.2 Idris and dependent types
Idris is a purely functional language that extends Haskell’s type system with full dependent types, allowing types to depend on values at runtime. While Haskell has gradually adopted dependently typed features (via extensions like DataKinds and TypeFamilies), Idris was designed from the ground up for theorem proving and verified programming. It draws direct inspiration from Haskell’s syntax and idioms.
6.3 PureScript and Elm
PureScript is a Haskell-like language that compiles to JavaScript, targeting web development with a strict, purely functional core and a practical module system. Elm is a simpler, more opinionated language for web frontends, emphasizing a friendly learning curve, no runtime exceptions, and a functional-reactive architecture. Both languages borrow heavily from Haskell’s type classes, algebraic data types, and monadic design patterns, but they trade some generality for accessibility and compile-time guarantees.