diff --git a/Art/Grammar.hs b/Art/Grammar.hs
--- a/Art/Grammar.hs
+++ b/Art/Grammar.hs
@@ -12,11 +12,16 @@
 -- | A production rule, including a starting probability of generation,
 --   a list of styles to be applied to sub-grammars, and a non-empty list of
 --   symbols to produce.
-type Production = (Float, [Modifier], NonEmpty Symbol)
+type Production = (Float, Symbol)
 
--- | A Terminal or non-terminal symbol.
+-- | A terminal or non-terminal symbol.
 data Symbol
+
+  -- | A non-terminal symbol.
   = NonTerminal (NonEmpty Production)
+
+  -- | Apply modifications to sub-productions.
+  | Mod [Modifier] Symbol
 
   -- | Produce a circle with a radius.
   | Circle Float
diff --git a/Art/Interpreter.hs b/Art/Interpreter.hs
--- a/Art/Interpreter.hs
+++ b/Art/Interpreter.hs
@@ -102,12 +102,10 @@
 sequenceRes rs = foldl joinRes emptyRes <$> sequence rs
 
 interpretNonTerminal :: State -> Production -> IO Res
-interpretNonTerminal state prod@(prob, mods, syms)
+interpretNonTerminal state prod@(prob, sym)
   = (< prob) . fromIntegral . in100 <$> randomIO
     >>= \case
-      True ->
-        let (newState, layerMod) = foldMods state mods
-        in second layerMod <$> sequenceRes (interpretSymbol newState <$> syms)
+      True -> interpretSymbol state sym
       False -> pure emptyRes
 
 interpretSymbol :: State -> Symbol -> IO Res
@@ -118,6 +116,9 @@
       sequenceRes (interpretNonTerminal state <$> (x :| y : ys))
     Circle r -> pure $ circle (r * scale) pos
     Poly pts -> pure $ poly state pts
+    Mod mods sym ->
+        let (newState, layerMod) = foldMods state mods
+        in second layerMod <$> interpretSymbol newState sym
 
 fourTupLst :: (a, a, a, a) -> [a]
 fourTupLst (a, b, c, d) = [a, b, c, d]
@@ -132,6 +133,8 @@
 boundsToViewBox (x1, y1, x2, y2) = (x1, y1, x2 - x1, y2 - y1)
 
 -- | Create a drawing from a grammar.
+--   In order to get a string representation, you'll need to use one of
+--   blaze-svg's render functions, for example 'renderSvg'.
 interpret :: Symbol -> IO S.Svg
 interpret sym =
   finalise <$> interpretSymbol emptyState sym
diff --git a/Tests.hs b/Tests.hs
--- a/Tests.hs
+++ b/Tests.hs
@@ -51,38 +51,39 @@
   = testRender "translated circle" a [5, 5, 2, 2]
       $ circle 1 (6, 6)
     where
-      a = NonTerminal $ (100, [Move (6, 6)], b :| []) :| []
+      a = Mod [Move (6, 6)] b
       b = Circle 1
 
 scaledCircle
   = testRender "scaled circle" a [-0.5, -0.5, 1, 1]
       $ circle 0.5 (0, 0)
     where
-      a = NonTerminal $ (100, [Scale 0.5], b :| []) :| []
+      a = Mod [Scale 0.5] b
       b = Circle 1
 
 translatedScaledCircle
   = testRender "translated scaled circle" a [10, 10, 4, 4]
       $ circle 2 (12, 12)
     where
-      a = NonTerminal $ (100, [Scale 2, Move (6, 6)], b :| []) :| []
+      a = Mod [Scale 2, Move (6, 6)] b
       b = Circle 1
 
 scaledTranslatedCircle
   = testRender "scaled translated circle" a [4, 4, 4, 4]
       $ circle 2 (6, 6)
     where
-      a = NonTerminal $ (100, [Move (6, 6), Scale 2], b :| []) :| []
+      a = Mod [Move (6, 6), Scale 2] b
       b = Circle 1
 
 multipleScaledTranslatedCircles
   = testRender "multiple symbols under one non-terminal" a [10, 10, 20, 20]
       $ circle 2 (12, 12) >> circle 2 (28, 28)
     where
-      a = NonTerminal $ (100, [Scale 2, Move (6, 6)], b :| [c]) :| []
+      a = Mod [Scale 2, Move (6, 6)] e
       b = Circle 1
-      c = NonTerminal $ (100, [Scale 2, Move (4, 4)], d :| []) :| []
+      c = Mod [Scale 2, Move (4, 4)] d
       d = Circle 0.5
+      e = NonTerminal $ (100, b) :| [(100, c)]
 
 rendersPoly
   = testRender "poly" a [0, 0, 2, 1]
@@ -94,25 +95,29 @@
   = testRender "translated poly" a [1, 1, 3, 2]
     $ path [(1, 1), (1, 1), (1, 0)]
     where
-      a = NonTerminal $ (100, [Move (1, 1)], Poly [(1, 1), (1, 0)] :| []) :| []
+      a = Mod [Move (1, 1)] b
+      b = Poly [(1, 1), (1, 0)]
 
 rendersPolyScaled
   = testRender "scaled poly" a [0, -3, 6, 6]
     $ path [(0, 0), (3, 3), (3, -6)]
     where
-      a = NonTerminal $ (100, [Scale 3], Poly [(1, 1), (1, -2)] :| []) :| []
+      a = Mod [Scale 3] b
+      b = Poly [(1, 1), (1, -2)]
 
 rendersPolyScaled2
   = testRender "another scaled poly" a [-4, 0, 4, 4]
     $ path [(0, 0), (-4, 4), (2, -4)]
     where
-      a = NonTerminal $ (100, [Scale 2], Poly [(-2, 2), (1, -2)] :| []) :| []
+      a = Mod [Scale 2] b
+      b = Poly [(-2, 2), (1, -2)]
 
 fill
   = testRender "another scaled poly" a [-1, -1, 2, 2]
     $ S.g ! A.fill "green" $ circle 1 (0, 0)
     where
-      a = NonTerminal $ (100, [Color "green"], Circle 1 :| []) :| []
+      a = Mod [Color "green"] b
+      b = Circle 1
 
 svgToText = TestCase $ do
   res <- renderSvg <$> interpret (Circle 1)
diff --git a/context-free-art.cabal b/context-free-art.cabal
--- a/context-free-art.cabal
+++ b/context-free-art.cabal
@@ -4,7 +4,7 @@
 -- http://haskell.org/cabal/users-guide/
 
 name:                context-free-art
-version:             0.1.0.0
+version:             0.2.0.0
 synopsis:            Generate art from context-free grammars
 description:
     .
@@ -27,16 +27,19 @@
     > import Art.ContextFree
     > import Data.List.NonEmpty
     >
-    > -- let's define a Production rule
+    > -- Let's define a Production rule
     > a = Circle 1
     >
-    > -- this will produce an IO Svg from the blaze-svg package
+    > -- This will produce an IO Svg from the blaze-svg package
     > -- to turn it into a string we can use one of the `blaze-svg` renderers
     > graphic1 = interpret $ Circle 1
     >
-    > -- let's create a non-terminal, at every layer,
-    > -- this will have an 85% chance of rendering another circle
-    > circles = NonTerminal $ (85, [Move (2, 0)], Circle 1 :| [circles]) :| []
+    > -- Let's create a non-terminal.
+    > -- At every layer, this will have an 85% chance
+    > -- of rendering another circle
+    > a = Mod [Move (2, 0)] b
+    > b = NonTerminal $ (85, c) :| []
+    > c = NonTerminal $ (100, Circle 1) :| [(100, a)]
 
 homepage:            https://github.com/414owen/context-free-art
 -- bug-reports:
