Skip to content

Latest commit

 

History

History
140 lines (76 loc) · 8.42 KB

File metadata and controls

140 lines (76 loc) · 8.42 KB

Why Stable Haskell?

The Problem: Stability and Integration

The Haskell ecosystem lacks a player focused on stability, backwards compatibility, and system integration for commercial use. This document explains the problem in depth and what Stable Haskell does about it.

Cross-Compilation

The inability to build high-quality Haskell applications for Windows from Linux was the original catalyst. Haskell's meta-programming capability (Template Haskell) is a fundamental inhibitor for cross-compilation. This also precludes compiling to iOS, Android, and WebAssembly.

This makes Haskell difficult to use in multi-platform settings: complex business logic needs to be reimplemented in different languages for different platforms. Contrast this with C, Go, and Rust, which handle this cleanly from a systems-engineering perspective.

Haskell, however, provides a very high-level language with a strong expressive type system that allows encoding program invariants with high ergonomics. It surpasses most languages in its elegance. The goal is to make it practical as well.

Proven in Production

IOG has used Haskell with great success to build a highly robust blockchain node for the Cardano project. The network has operated for years with little or no downtime across multiple network upgrades (hard forks). Haskell can be made to work in high-demand production settings.

It is also used in other high-assurance environments: Mercury Bank, Standard Chartered, Juspay, and others.

The Challenges of Production Usage

Using Haskell in production comes with specific challenges:

  • Academic development pace. GHC is developed in an academic fashion and takes breaking changes with each iteration lightly.
  • Bespoke build system. GHC uses its own intricate build system, raising the barrier to contribution.
  • Slow contribution cycle. Improvements must target the master branch of the currently-in-development compiler. CI runs frequently take hours and fail for unrelated reasons. Backports and minor releases are infrequent.
  • Ecosystem cascade. Every compiler release forces updates across Hackage libraries. Only the minority of maintainers also update older releases, so upgrading the compiler means upgrading everything it depends on too.

The Maintenance Burden

IOG was stuck at GHC 8.10 for a long time due to a regression. After finding and fixing it, getting an upstream release took additional months.

Breaking changes in the compiler are continuous. IOG employed at least one full-time engineer solely to upgrade its codebase and maintain compatibility with new compiler versions for regression testing.

Build Tool Deficiencies

Haskell's two major build tools — cabal-install and stack — both lack an understanding of build/host compiler separation:

  • Build compiler: produces executables for the machine being built on
  • Host compiler: produces executables for the deployment target

In the simple case, host = build. For cross-compilation, they differ. Neither tool handles this well, and GHC itself conflates the two.


The Solution: Stable Haskell

Stable Haskell (GHC Stable Haskell Edition) addresses these problems through a set of concrete design goals.

1. Agile Releases

A simple, fast, and predictable release process enables frequent releases. This makes backports practical and reduces the gap between fixing a regression and shipping it.

2. Simplified Contribution

The compiler is built on GitHub (rather than a custom GitLab instance) using cabal-install rather than the bespoke GHC build system. This lowers the barrier to entry and should broaden the contributor base.

To build with cabal-install:

  • cabal-install learns about build/host separation
  • All compiler-dependent libraries (RTS, FFI, etc.) are buildable with cabal-install
  • Build "ways" and flavours are simplified

3. Multi-Target

The compiler is multi-target (-target=…). A single compiler binary handles multiple output targets — Windows, static, JavaScript, WASM, mobile — rather than requiring separate builds. This significantly reduces compiler size in multi-target settings and makes Haskell reuse across platforms practical.

4. Minimal Distribution

The compiler ships only the absolutely necessary libraries. Everything else is built on demand. This reduces installation size and startup friction.

5. Self-Contained

The binary distribution is a simple zip archive: download, unzip, run. No configure, no make install, no hardcoded paths baked in at install time.

This also makes the compiler resilient to system changes (updated LLVM, libc, C compilers). Identical inputs produce identical outputs, enabling better caching and artifact sharing among developers.


Technical Design Decisions

External Interpreter (iserv) as Default

GHC's dynamic execution (GHCi) and Template Haskell compilation exist in two modes:

  1. Internal — built into the GHC executable; requires identical ABI
  2. External — via iserv, a separate process

The internal interpreter requires a different compiler executable per ABI. The external interpreter (iserv) is the only viable architecture for cross-compilation, and it is the significantly better architecture generally.

Stable Haskell defaults to iserv and builds the necessary iserv executable on demand. This simplifies the compiler and allows changing "boot" libraries (e.g., ghc-bignum) without rebuilding everything.

Profiling ABI Compatibility

Currently, GHC's instrumented profiling mode is ABI-incompatible with non-profiling mode. Stable Haskell treats profiling like any other library, making it ABI-compatible. This eliminates the combinatorial explosion of "ways" and flavours that currently complicate cross-compilation.

Linking Strategy

  • Development: always produce Position Independent Code (PIC / "dynamic") and use shared objects for libraries. This lets GHC use the system linker, which is substantially faster than GHC's internal static linker.
  • Cross-compilation: the internal static linker remains valuable and is preserved for this use case.

On modern 64-bit CPUs with large caches and branch prediction, PIC is almost always the right default.


The Role of haskell.nix

IOG currently relies on haskell.nix to paper over many of GHC's deficiencies. It provides reliable reproducibility, exact dependency pinning, and supply-chain stability — and it has been extremely successful as a prototyping and integration vehicle.

However, Nix itself remains a barrier to entry. It produces poor user experiences and arcane error messages. And as GHC's build system changes internally, haskell.nix continuously accumulates complexity to compensate.

Stable Haskell moves large parts of this prototyped functionality into the compiler itself, so that non-Nix setups can achieve the same fidelity. As a result, haskell.nix can be aggressively simplified — errors will originate from the compiler directly rather than layers of Nix abstraction.

This is not a criticism of haskell.nix. It is one of IOG's most successful open source projects. But papering over compiler deficiencies indefinitely is not a sustainable path.


Commercial and Community Vision

IOG has been involved in GHC calls, the GHC Steering Committee, Core Libraries Committee, Haskell.org Committee, and the Haskell Foundation for years. Progress on fundamental stability and architecture has been slow; many engineering directions have been acknowledged but not acted on.

Stable Haskell is the result of deciding to demonstrate rather than advocate.

Internal velocity first. Stable Haskell supports IOG's own development teams with a faster, lower-friction compiler.

Commercial offering second. We offer support contracts for the Stable Haskell compiler — effectively formalising the support IOG already provides to external Haskell companies. This includes dev shells, cross-compilation setups, and build infrastructure.

The Deliverable

The Stable Haskell distribution includes everything a Haskell developer needs:

  • GHC — multi-target, self-contained, cabal-first
  • cabal-install — with build/host separation support
  • HLS — Haskell Language Server

User experience: download, unzip, run. Drop-in compatible with upstream GHC's CLI; incompatible flags produce a high-quality error message with rationale.


We upstream our fixes to GHC and Cabal. A rising tide lifts all lambdas.