Unison is a functional programming language where code is stored as a hash-addressed content database — not text files. This means no build errors from dependency conflicts, instant code sharing, and effortless distributed computing.
Why Unison Matters
Every programming language stores code as text in files. This causes: dependency hell, merge conflicts on renames, broken imports, and the inability to safely share code. Unison stores code by its hash — like Git stores content.
What you get for free:
- Content-addressed code: no dependency conflicts ever
- Rename anything without breaking anything
- Built-in distributed computing (send functions to remote nodes)
- Instant code sharing via Unison Share
- Structural typing — if it fits, it works
- Algebraic effects for clean side-effect handling
- Built-in test framework
Quick Start
# Install
curl -fsSL https://www.unison-lang.org/install | sh
# Start the Unison codebase manager
ucm
# Create a new project
.> project.create myproject
# Edit code
myproject/main> edit myFunction
The Basics
-- Functions
greet : Text -> Text
greet name = "Hello, " ++ name ++ "!"
-- Pattern matching
fibonacci : Nat -> Nat
fibonacci = cases
0 -> 0
1 -> 1
n -> fibonacci (n - 1) + fibonacci (n - 2)
-- Lists and higher-order functions
doubleEvens : [Nat] -> [Nat]
doubleEvens list =
list
|> List.filter (n -> Nat.mod n 2 == 0)
|> List.map (n -> n * 2)
-- Result types
parseAge : Text -> Either Text Nat
parseAge input =
match Nat.fromText input with
Some n | n > 0 && n < 150 -> Right n
_ -> Left "Invalid age"
Distributed Computing
-- Send a computation to a remote node
remoteCompute : Node -> Nat -> {Remote} Nat
remoteCompute node input =
Remote.at node do
-- This code runs on the remote node
heavyComputation input
-- Fan out work across multiple nodes
parallelMap : [Node] -> (a -> b) -> [a] -> {Remote} [b]
parallelMap nodes f items =
List.zip nodes items
|> List.map (cases (node, item) ->
Remote.at node do f item)
|> Remote.collectAll
Abilities (Algebraic Effects)
-- Define an ability (like an interface for side effects)
ability Store where
get : Key -> Optional Value
put : Key -> Value -> ()
delete : Key -> ()
-- Use the ability in functions
cacheOrCompute : Key -> '{Store, Exception} Value
cacheOrCompute key = do
match Store.get key with
Some value -> value
None ->
let result = expensiveComputation key
Store.put key result
result
-- Provide different implementations
handleWithMap : Map Key Value -> Request {Store} a -> a
handleWithMap map = cases
{ Store.get key -> resume } ->
handleWithMap map (resume (Map.get key map))
{ Store.put key value -> resume } ->
handleWithMap (Map.insert key value map) (resume ())
{ result } -> result
Content-Addressed Magic
-- In traditional languages:
-- 1. Rename function -> all imports break
-- 2. Update dependency -> version conflicts
-- 3. Move file -> everything breaks
-- In Unison:
-- 1. Rename function -> nothing breaks (code is stored by hash)
-- 2. Update dependency -> old version still works (different hash)
-- 3. There are no files -> nothing to move
Testing
test> fibonacci.tests = do
ensureEqual (fibonacci 0) 0
ensureEqual (fibonacci 1) 1
ensureEqual (fibonacci 10) 55
ensureEqual (fibonacci 20) 6765
test> greet.tests = do
ensureEqual (greet "World") "Hello, World!"
ensureEqual (greet "") "Hello, !"
Useful Links
- Official Site
- GitHub
- Unison Share — code sharing platform
- Learn Unison
Building innovative developer tools? Check out my developer tools on Apify for ready-made web scrapers, or email spinov001@gmail.com for custom solutions.
Top comments (0)