Haskell excels at high-performance, correct server programs. Today covers the Scotty web framework, concurrent programming with STM, and packaging with Cabal and Stack.
Scotty is a lightweight web framework inspired by Ruby's Sinatra. Routes are defined with get, post, put, delete, taking a pattern and an action in the ActionM monad. param extracts path/query parameters; json sends JSON responses; html sends HTML. Scotty runs on Warp, a high-performance Haskell HTTP server — benchmarks show Warp handling hundreds of thousands of requests per second.
STM provides composable, lock-free concurrency. TVar is a shared mutable variable. atomically executes a transaction: all reads and writes succeed together or the transaction retries from scratch. No deadlocks possible — STM detects conflicts automatically. This is far simpler than mutex-based concurrency: you cannot forget to acquire a lock because the type system forces all shared state through atomically.
Cabal is Haskell's build tool and package manager. A .cabal file lists dependencies, modules, and build options. Stack wraps Cabal with reproducible builds via LTS (Long Term Support) Stackage snapshots — a known set of mutually compatible package versions. Create a project: 'stack new myproject', add dependencies to package.yaml, run 'stack build' and 'stack test'. Hackage hosts 16,000+ Haskell packages.
{-# LANGUAGE OverloadedStrings #-}
import Web.Scotty
import Control.Concurrent.STM
import Data.Text.Lazy (Text)
import qualified Data.Map.Strict as Map
type KVStore = TVar (Map.Map Text Text)
main :: IO ()
main = do
store <- newTVarIO Map.empty
scotty 3000 $ do
-- GET /kv/:key
get "/kv/:key" $ do
k <- param "key"
m <- liftIO $ readTVarIO store
case Map.lookup k m of
Nothing -> text "Not found"
Just v -> text v
-- PUT /kv/:key with body as value
put "/kv/:key" $ do
k <- param "key"
v <- body
liftIO $ atomically $
modifyTVar store (Map.insert k (lazyTextFromStrict v))
text "OK"
where lazyTextFromStrict = id -- simplified
Build a complete Haskell REST API for a todo list: POST /todos (create), GET /todos (list all), GET /todos/:id (get one), DELETE /todos/:id (delete). Store data in a TVar Map. Return JSON using Aeson. Write 5 curl-based integration tests.