Concurrent Clean
A purely functional programming language based on graph rewriting, featuring uniqueness typing as an alternative to monads for handling state and I/O.
Created by Software Technology Research Group, Radboud University Nijmegen (Rinus Plasmeijer, Marko van Eekelen)
Concurrent Clean, now commonly known simply as Clean, is a purely functional programming language developed at Radboud University Nijmegen in the Netherlands. Its most distinctive contribution to programming language theory is its uniqueness type system, which provides an elegant alternative to Haskell’s monads for handling mutable state and I/O while preserving referential transparency. Built on a formal foundation of term graph rewriting, Clean occupies a unique position in the functional programming landscape as both a research vehicle and a practical language.
History & Origins
The Parallel Reduction Machine
Clean’s story begins in 1984 at what was then the Catholic University of Nijmegen (now Radboud University Nijmegen) in the Netherlands. The Software Technology Research Group, led by Rinus Plasmeijer and Marko van Eekelen, began developing Clean as part of the Parallel Reduction Machine project. The goal was to create a language that could express parallel computations through graph rewriting.
The first operational version was completed in 1987 and presented at the FPCA ‘87 conference (Third International Conference on Functional Programming Languages and Computer Architecture) in Portland, Oregon. At this point, the language was known as the Concurrent Clean System, with “Concurrent” reflecting its origins in parallel computation.
Relationship with Haskell
Clean and Haskell are close relatives that developed in parallel during the late 1980s and early 1990s. Both were influenced by Miranda, share lazy evaluation semantics, and have similar syntax. However, they diverged on a fundamental design question: how should a purely functional language handle side effects?
- Haskell chose monads, using a type constructor (
IO) to encapsulate effectful computations. - Clean chose uniqueness types, a type system feature that guarantees at most one reference to a value exists, enabling safe in-place mutation.
The two languages influenced each other during development. Clean is slightly older (1987 vs. Haskell’s 1990 first release), and ideas flowed in both directions.
From Concurrent Clean to Clean
The full name “Concurrent Clean” was gradually simplified to just “Clean” as the language evolved. According to the official FAQ, “Concurrent Clean” is essentially a synonym for the Clean 1.0 era. The original “Concurrent” referred to the language’s ability to run processes on multiple computers. The shorter name was adopted for convenience, though “Concurrent Clean” persists in some references partly because the word “Clean” alone is difficult to search for on the internet.
Design Philosophy
Graph Rewriting Foundation
Clean is formally based on Term Graph Rewriting Systems (TGRSs). Unlike most functional languages where functions operate on terms (tree structures), Clean’s functions semantically operate on graphs. This means:
- Sharing is explicit: Two expressions can refer to the same underlying data, and this sharing is part of the language semantics.
- Cyclic structures: Clean can define and work with cyclic data structures directly.
- Efficient reduction: The graph rewriting model maps naturally to efficient machine implementations.
// Clean uses graph rewriting semantics
// This definition creates shared subexpressions
Start = let x = expensive_computation in (x, x)
// 'expensive_computation' is evaluated only once due to sharing
Uniqueness Typing
Clean’s most distinctive feature is its uniqueness type system. A value marked as unique (with *) is guaranteed to have exactly one reference pointing to it. This guarantee allows the compiler to perform destructive (in-place) updates safely, without violating referential transparency.
// The *World type is unique - only one reference exists
Start :: *World -> *World
Start world
# (console, world) = stdio world
# console = fwritec 'H' console
# console = fwrites "ello, World!\n" console
# (ok, world) = fclose console world
= world
In this example, the *World value represents the state of the external world. Because it is unique, the compiler knows it can be updated in place. This achieves the same referential transparency as Haskell’s IO monad but through a type system mechanism rather than a monadic abstraction.
The uniqueness type system has several advantages:
- Efficient I/O: File handles, arrays, and the world state can be updated in place.
- No monadic overhead: Programmers don’t need to structure code monadically.
- Destructive array updates: Unique arrays can be modified in O(1) time rather than copied.
Purity and Laziness
Like Haskell, Clean is:
- Purely functional: Functions have no side effects; all effects are managed through the type system.
- Lazy by default: Expressions are evaluated only when their values are needed.
- Strongly and statically typed: The type system catches errors at compile time, with type inference reducing annotation burden.
Key Features
Generic Programming
Clean supports generic programming, allowing functions to be defined once and automatically derived for any data type:
// A generic equality function works for any type
generic gEq a :: a a -> Bool
// Derive equality for specific types automatically
derive gEq Int, Bool, [], (,)
Dynamic Types
Since Clean 2.0, the language supports dynamic types, allowing values to carry their type information at runtime:
// Pack a value with its type
dynamic_value :: Dynamic
dynamic_value = dynamic 42
// Unpack and use at runtime
use_dynamic :: Dynamic -> String
use_dynamic (x :: Int) = toString x
use_dynamic _ = "not an integer"
This feature enables dynamic linking and runtime code loading while maintaining type safety.
Records and Algebraic Types
Clean provides algebraic data types similar to Haskell’s:
// Algebraic data type
:: Tree a = Leaf | Node a (Tree a) (Tree a)
// Record type with named fields
:: Person = { name :: String
, age :: Int
}
List Comprehensions and Guards
// List comprehension
evens = [x \\ x <- [1..100] | isEven x]
// Function with guards
abs :: Int -> Int
abs x
| x < 0 = ~x
| otherwise = x
The Clean IDE
Clean comes with its own integrated development environment, which has traditionally been a focus of the project. The Clean IDE provides project management, editing, and compilation facilities. While not as feature-rich as modern IDEs, it provides a complete development workflow for Clean programs.
iTasks and Task-Oriented Programming
One of Clean’s most significant contemporary contributions is the iTasks framework, a domain-specific language embedded in Clean for Task-Oriented Programming (TOP). iTasks enables the creation of multi-user, web-based workflow applications from high-level task descriptions.
In the TOP paradigm, programmers describe what needs to be done rather than how to present it. The framework automatically generates web interfaces, handles user interaction, and manages task coordination. This approach has been applied to real-world systems, particularly through the TOP Software Technology spin-off company founded in 2018.
Evolution
Clean has undergone significant evolution since its first appearance:
- Clean 1.0 (1995): Transition from research intermediate language to general-purpose functional language. Available on Macintosh and PC/OS2.
- Clean 2.0 (2001): Major release adding dynamic types, dynamic linking, and the Sparkle proof tool.
- Clean 2.1 (2003): Expanded platform support to macOS X, Linux, and Solaris.
- Clean 2.2 (2006): Added 64-bit Intel support and distributed the complete source code.
- Clean 3.0 (2018): Modernized release for Windows, Linux, and macOS.
- Clean 3.1 (2022): The latest stable release.
A package manager called Nitrile has been developed, with packages available through the Clean language website.
Current Relevance
Clean remains an active but niche language. Its primary home continues to be Radboud University Nijmegen, where it is used for both research and teaching. The TOP Software Technology company applies Clean in commercial settings, particularly for command and control systems.
The source code is available on GitLab, and the language supports Windows, macOS, and Linux. While Clean’s user base is small compared to Haskell, the language continues to contribute ideas to the broader functional programming community.
Clean’s uniqueness typing system has gained renewed interest as other languages explore substructural type systems. Rust’s ownership model, while different in implementation, shares the philosophical insight that tracking how many references exist to a value enables both safety and performance.
Why It Matters
Concurrent Clean matters for several reasons:
Uniqueness types as an alternative to monads: Clean demonstrated that purely functional I/O doesn’t require monads, offering an approach based on type-level uniqueness guarantees instead.
Graph rewriting semantics: Clean’s formal foundation in term graph rewriting provided a rigorous mathematical basis for lazy functional language implementation.
Mutual influence with Haskell: As a close relative of Haskell that made different design choices, Clean serves as a valuable point of comparison in programming language research.
Task-Oriented Programming: The iTasks framework pioneered a declarative approach to building interactive multi-user applications that continues to influence research in this area.
Substructural type systems: Clean’s uniqueness types were an early practical demonstration of substructural typing, a concept that has since influenced languages like Rust.
Getting Started
Clean source files use the .icl extension (implementation) and .dcl extension (definition/interface). A basic Clean program:
module hello
import StdEnv
Start :: *World -> *World
Start world
# (console, world) = stdio world
# console = fwrites "Hello, World!\n" console
# (ok, world) = fclose console world
= world
Clean can be downloaded from the official website at clean-lang.org. The language is available for Windows, macOS, and Linux.
Timeline
Notable Uses & Legacy
iTasks Framework
A domain-specific language embedded in Clean for Task-Oriented Programming, used to build multi-user web-based workflow applications
TOP Software Technology
Spin-off company from Radboud University using Clean for command and control systems, including maritime monitoring and incident coordination for the Netherlands Coast Guard
Sparkle Proof Assistant
A theorem prover for Clean programs, enabling formal verification of functional programs written in Clean
Academic Research at Radboud University
Extensively used for research in functional programming, type systems, graph rewriting semantics, and Task-Oriented Programming