diff --git a/README.md b/README.md
--- a/README.md
+++ b/README.md
@@ -4,12 +4,14 @@
 
 A purely functional E-Graph library
 
-## How to build and run
+## Quick start
 
+If you have `stack` installed (see below), try `make ghci` to hop into a REPL. Then try `exampleMain` or anything else from the `Overeasy.Example` module.
+
+## More on how to build and run
+
 This repo is setup so you never have to `cd` out of the root directory.
 
 To run the Haskell programs, you need `stack` installed on your system. [This](https://docs.haskellstack.org/en/stable/README/) is an easy way to do so, but you can also check your package manager or use [ghcup](https://www.haskell.org/ghcup/).
 
 Most of the interesting stuff is going to be run in the test suite. Run it with `make test`. `stack` will get the appropriate Haskell compiler and package dependencies, and it will compile the project before running the test suite.
-
-If you have Docker installed and running (with about 4G of RAM allocated to it), you can run `make docker-test` to build and run tests in a container instead of installing `stack` locally.
diff --git a/overeasy.cabal b/overeasy.cabal
--- a/overeasy.cabal
+++ b/overeasy.cabal
@@ -5,7 +5,7 @@
 -- see: https://github.com/sol/hpack
 
 name:           overeasy
-version:        0.1.0
+version:        0.1.1
 synopsis:       A purely functional E-Graph library
 description:    Please see the README on GitHub at <https://github.com/ejconlon/overeasy#readme>
 category:       Data Structures
@@ -29,6 +29,7 @@
       Overeasy.Assoc
       Overeasy.EGraph
       Overeasy.EquivFind
+      Overeasy.Example
       Overeasy.Matching
       Overeasy.Source
       Overeasy.Streams
@@ -84,7 +85,6 @@
   type: exitcode-stdio-1.0
   main-is: Main.hs
   other-modules:
-      Test.Overeasy.Arith
       Test.Overeasy.BinTree
       Paths_overeasy
   hs-source-dirs:
diff --git a/src/Overeasy/Example.hs b/src/Overeasy/Example.hs
new file mode 100644
--- /dev/null
+++ b/src/Overeasy/Example.hs
@@ -0,0 +1,76 @@
+{-# LANGUAGE DeriveAnyClass #-}
+{-# LANGUAGE TemplateHaskell #-}
+
+-- | An example using arithmetic expressions.
+module Overeasy.Example
+  ( Arith (..)
+  , ArithF (..)
+  , exampleGraph
+  , examplePat
+  , exampleMain
+  ) where
+
+import Control.DeepSeq (NFData)
+import Control.Monad.State.Strict (execState)
+import Data.Functor.Foldable.TH (makeBaseFunctor)
+import Data.Hashable (Hashable)
+import GHC.Generics (Generic)
+import Overeasy.EGraph (EClassId (..), EGraph, egAddTerm, egMerge, egNew, noAnalysis)
+import Overeasy.Matching (Pat, match)
+import Unfree (pattern FreeEmbed, pattern FreePure)
+
+-- | Arithmetic expressions.
+-- 'ArithF' is the base functor for this type.
+data Arith =
+    ArithPlus Arith Arith
+  | ArithTimes Arith Arith
+  | ArithShiftL Arith !Int
+  | ArithShiftR Arith !Int
+  | ArithConst !Int
+  deriving stock (Eq, Show, Generic)
+  deriving anyclass (Hashable, NFData)
+
+-- Generates 'ArithF' and other recursion-schemes boilerplate
+makeBaseFunctor ''Arith
+
+deriving stock instance Eq a => Eq (ArithF a)
+deriving stock instance Show a => Show (ArithF a)
+deriving stock instance Generic (ArithF a)
+deriving anyclass instance Hashable a => Hashable (ArithF a)
+deriving anyclass instance NFData a => NFData (ArithF a)
+
+-- | Creates a simple e-graph with the equality `2 + 2 = 4`.
+exampleGraph :: EGraph () ArithF
+exampleGraph = flip execState egNew $ do
+  -- We don't need to analyze here.
+  let ana = noAnalysis
+  -- Some simple terms:
+  let termFour = ArithConst 4
+      termTwo = ArithConst 2
+      termPlus = ArithPlus termTwo termTwo
+  -- Add the term `4`
+  (_, cidFour) <- egAddTerm ana termFour
+  -- Add the term `2`
+  (_, _cidTwo) <- egAddTerm ana termTwo
+  -- Add the term `2 + 2`
+  (_, cidPlus) <- egAddTerm ana termPlus
+  -- Merge `4` and `2 + 2`
+  _ <- egMerge cidFour cidPlus
+  pure ()
+
+-- | Creates a simple pattern to match nodes like `x + x`.
+examplePat :: Pat ArithF String
+examplePat = FreeEmbed (ArithPlusF (FreePure "x") (FreePure "x"))
+
+-- | Build an e-graph, e-match on it, and print the result.
+exampleMain :: IO ()
+exampleMain = do
+  let eg = exampleGraph
+  putStrLn "e-graph:"
+  print eg
+  let pat = examplePat
+  putStrLn "pattern:"
+  print pat
+  let results = match pat eg
+  putStrLn "e-matches:"
+  print results
diff --git a/test/Main.hs b/test/Main.hs
--- a/test/Main.hs
+++ b/test/Main.hs
@@ -34,11 +34,11 @@
                         noAnalysis)
 import Overeasy.EquivFind (EquivFind (..), efAdd, efCanCompact, efCompact, efFindRoot, efLeaves, efLeavesSize, efMember,
                            efMembers, efMerge, efMergeSets, efNew, efRemoveAll, efRoots, efRootsSize, efTotalSize)
+import Overeasy.Example (Arith (..), ArithF (..))
 import Overeasy.Matching (Match (..), MatchPat (..), MatchSubst (..), Pat, match)
 import Overeasy.Util (Changed (..))
 import PropUnit (DependencyType (..), Gen, MonadTest, PropertyT, Range, TestLimit, TestTree, after, assert, forAll,
                  testGroup, testMain, testProp, testUnit, (/==), (===))
-import Test.Overeasy.Arith (Arith (..), ArithF (ArithPlusF))
 import Test.Overeasy.BinTree (BinTree, pattern BinTreeBranch, BinTreeF (..), pattern BinTreeLeaf)
 import Unfree (pattern FreeEmbed, pattern FreePure)
 
diff --git a/test/Test/Overeasy/Arith.hs b/test/Test/Overeasy/Arith.hs
deleted file mode 100644
--- a/test/Test/Overeasy/Arith.hs
+++ /dev/null
@@ -1,30 +0,0 @@
-{-# LANGUAGE DeriveAnyClass #-}
-{-# LANGUAGE TemplateHaskell #-}
-
-module Test.Overeasy.Arith
-  ( ArithF (..)
-  , Arith (..)
-  ) where
-
-import Control.DeepSeq (NFData)
-import Data.Functor.Foldable.TH (makeBaseFunctor)
-import Data.Hashable (Hashable)
-import GHC.Generics (Generic)
-
-data Arith =
-    ArithPlus Arith Arith
-  | ArithTimes Arith Arith
-  | ArithShiftL Arith !Int
-  | ArithShiftR Arith !Int
-  | ArithConst !Int
-  deriving stock (Eq, Show, Generic)
-  deriving anyclass (Hashable, NFData)
-
--- Generates 'ArithF' and other recursion-schemes boilerplate
-makeBaseFunctor ''Arith
-
-deriving stock instance Eq a => Eq (ArithF a)
-deriving stock instance Show a => Show (ArithF a)
-deriving stock instance Generic (ArithF a)
-deriving anyclass instance Hashable a => Hashable (ArithF a)
-deriving anyclass instance NFData a => NFData (ArithF a)
