Haskell
Pure functions, powerful types.
Haskell is a purely functional language with a strong static type system and lazy evaluation. It changes how you think about programming, and its ideas (type inference, monads, immutability) now shape Rust, Scala, Swift, TypeScript and modern ML frameworks.
Why learn Haskell?
Even if you never ship Haskell in production, learning it makes you a better programmer in every other language.
- Correctness: the type checker catches whole classes of bugs before your code runs.
- Pure functions: no hidden state, so code is easy to test and reason about.
- Ideas that spread: functional patterns used in JAX, React and Rust started here.
Set up and run your first program
Install GHCup, which gives you GHC, the Cabal build tool and the Haskell language server.
curl --proto '=https' --tlsv1.2 -sSf https://get-ghcup.haskell.org | sh
ghc --version
runghc hello.hsmain :: IO ()
main = do
let name = "Ada"
putStrLn ("Hello, AI! Welcome to Haskell, " ++ name ++ ".")ghci for an interactive prompt: load a file with :load hello.hs.Values and types
Values never change once defined. Type signatures are optional because GHC infers them, but writing them documents your code.
layers :: Int
layers = 32
lr :: Double
lr = 3e-4
fp16GB :: Double -> Double
fp16GB params = params * 2 / 1e9
main :: IO ()
main = print (fp16GB 8.03e9) -- 16.06Functions and pattern matching
Functions are defined by equations and pattern matching. All functions are curried, so you can apply them partially.
precision :: Int -> String
precision 32 = "FP32"
precision 16 = "FP16"
precision 8 = "FP8"
precision _ = "other"
scale :: Double -> Double -> Double
scale k x = k * x
double :: Double -> Double
double = scale 2 -- partial application
main = do
putStrLn (precision 8)
print (double 21)Lists and higher-order functions
map, filter and foldr replace most loops. List comprehensions read like maths.
vram :: [(String, Int)]
vram = [("H100", 80), ("H200", 141), ("RTX 5090", 32)]
big :: [String]
big = [name | (name, gb) <- vram, gb >= 80]
total :: Int
total = sum (map snd vram)
main = do
print big -- ["H100","H200"]
print total
print (foldr (+) 0 [1..10])Custom data types
Define your own types with data. The compiler checks that every case is handled. Maybe replaces null.
data Device = CPU | GPU String Int deriving Show
memory :: Device -> Maybe Int
memory CPU = Nothing
memory (GPU _ gb) = Just gb
describe :: Device -> String
describe d = case memory d of
Nothing -> "no dedicated memory"
Just gb -> show gb ++ " GB of VRAM"
main = mapM_ (putStrLn . describe) [CPU, GPU "H100" 80]IO and do notation
Side effects live in the IO type, so pure and impure code stay separate. do blocks sequence actions.
import qualified Data.Map as M
main :: IO ()
main = do
text <- readFile "notes.txt"
let counts = M.fromListWith (+) [(w, 1 :: Int) | w <- words text]
mapM_ print (take 5 (M.toList counts))AI with Haskell
Haskell is not a mainstream ML language, but it has typed tensor libraries and is used to build safe AI tooling, compilers for ML hardware and LLM clients. Its ideas of pure functions and function transformations are at the heart of JAX.
The essential libraries
Gradient descent from scratch
Fit y = 3x + 0.5 with pure functions and a fold.
xs, ys :: [Double]
xs = [-1, -0.98 .. 1]
ys = map (\x -> 3 * x + 0.5) xs
step :: (Double, Double) -> Int -> (Double, Double)
step (w, b) _ = (w - lr * gw, b - lr * gb)
where
lr = 0.1
n = fromIntegral (length xs)
errs = zipWith (\x y -> w * x + b - y) xs ys
gw = 2 / n * sum (zipWith (*) errs xs)
gb = 2 / n * sum errs
main = print (foldl step (0, 0) [1 .. 500]) -- about (3.0, 0.5)Build an AI agent in Haskell
With http-conduit and aeson you can run a tool-calling loop against a local model. Types make the message format explicit.
{-# LANGUAGE OverloadedStrings #-}
import Network.HTTP.Simple
import Data.Aeson
import Data.Aeson.Lens -- from the lens-aeson package
import Control.Lens ((^?), (^..))
import qualified Data.Vector as V
tools :: Value
tools = toJSON [object ["type" .= ("function" :: String), "function" .= object
[ "name" .= ("get_weather" :: String), "description" .= ("Weather for a city" :: String)
, "parameters" .= object ["type" .= ("object" :: String)
, "properties" .= object ["city" .= object ["type" .= ("string" :: String)]]
, "required" .= ["city" :: String]]]]]
chat :: [Value] -> IO Value
chat msgs = do
let req = setRequestBodyJSON (object ["model" .= ("llama3.1" :: String), "messages" .= msgs, "tools" .= tools])
$ "POST http://localhost:11434/v1/chat/completions"
getResponseBody <$> httpJSON req
loop :: Int -> [Value] -> IO ()
loop 0 _ = putStrLn "gave up"
loop n msgs = do
res <- chat msgs
let Just msg = res ^? key "choices" . nth 0 . key "message"
calls = msg ^.. key "tool_calls" . values
if null calls then print (msg ^? key "content" . _String) else do
let reply c = object [ "role" .= ("tool" :: String), "tool_call_id" .= (c ^? key "id" . _String)
, "content" .= ("It is 24°C and sunny." :: String) ]
loop (n - 1) (msgs ++ [msg] ++ map reply calls)
main = loop 5 [object ["role" .= ("user" :: String), "content" .= ("Should I take an umbrella in Lahore today?" :: String)]]Add the packages http-conduit, aeson, lens-aeson, lens and vector to your Cabal file.
ollama pull llama3.1, and keep it running. The code talks to its OpenAI-compatible API at http://localhost:11434/v1, so the same program also works with vLLM, llama.cpp server or a cloud API by changing the URL, model name and adding an API key.Haskell learning roadmap
Tick items off as you go. Your progress is saved in this browser.
Beginner
Intermediate
Advanced
Projects to build
Haskell cheat sheet
| Task | Syntax |
|---|---|
| Function | add x y = x + y |
| Type signature | add :: Int -> Int -> Int |
| Lambda | \x -> x * 2 |
| List comprehension | [x*x | x <- [1..5]] |
| Pattern match | case m of Just x -> x; Nothing -> 0 |
| Compose | (f . g) x |
Common mistakes
- Laziness can build up huge unevaluated expressions; use strict folds like
foldl'. head []crashes; prefer pattern matching or Maybe.- Indentation matters inside
do,letandwhereblocks.
Where to go next
- Learn You a Haskell — free book
- Haskell.org — official site
- Hoogle — search functions by type
On TensorCore.si: Rust volume, Scala volume.
Keyboard: [ previous language · ] next language · / search the library