diff --git a/Main.hs b/Main.hs
--- a/Main.hs
+++ b/Main.hs
@@ -3,14 +3,17 @@
 {-# LANGUAGE OverloadedStrings #-}
 
 import           Control.Applicative
+import           Control.Lens.Cons
 import           Control.Lens.SemiIso
 import           Control.Lens.TH
 import qualified Data.Attoparsec.Text as AP
 import           Data.Char
+import           Data.Scientific (Scientific)
 import           Data.SemiIsoFunctor
 import           Data.Syntax (Syntax)
 import qualified Data.Syntax as S
 import qualified Data.Syntax.Attoparsec.Text as S
+import           Data.Syntax.Char (SyntaxChar)
 import qualified Data.Syntax.Char as S
 import qualified Data.Syntax.Combinator as S
 import qualified Data.Syntax.Pretty as S
@@ -18,37 +21,68 @@
 import qualified Data.Text.IO as T
 import qualified Text.PrettyPrint as P
 
--- | A simple untyped lambda calculus.
+-- A simple lambda calculus.
+
+data Literal = LitStr Text
+             | LitNum Scientific
+    deriving (Show)
+
+$(makePrisms ''Literal)
+
 data AST = Var Text
+         | Lit Literal
          | App AST AST
          | Abs Text AST
+         | Let Text AST AST
     deriving (Show)
 
 $(makePrisms ''AST)
 
 -- | A variable name.
 name :: Syntax syn Text => syn Text
-name = S.takeWhile1 isAlphaNum
+name = _Cons /$/ S.satisfy isAlpha /*/ S.takeWhile isAlphaNum
 
+-- | A quoted string.
+quoted :: SyntaxChar syn seq => syn seq
+quoted = S.char '"' */ S.takeTill (=='"') /* S.char '"'
+
 -- | Encloses a symbol in parentheses.
-parens :: Syntax syn Text => syn a -> syn a
+parens :: SyntaxChar syn seq => syn a -> syn a
 parens m = S.char '(' */ S.spaces_ */ m /* S.spaces_ /* S.char ')'
 
--- | An atom is a variable or an expression in parentheses.
-atom :: Syntax syn Text => syn AST
-atom =  _Var /$/ name
+-- | A literal.
+literal :: SyntaxChar syn Text => syn Literal
+literal =  _LitNum /$/ S.scientific
+       /|/ _LitStr /$/ quoted
+
+-- | An atom is a variable, literal or an expression in parentheses.
+atom :: SyntaxChar syn Text => syn AST
+atom =  _Lit /$/ literal
+    /|/ _Var /$/ name
     /|/ parens expr
 
--- | Parsers a list of applications.
-apps :: Syntax syn Text => syn AST
-apps = bifoldl1 (attemptAp_ _App) /$/ S.sepBy1 atom S.spaces1
+-- | Parses a list of atoms and folds them with the _App prism.
+apps :: SyntaxChar syn Text => syn AST
+apps = bifoldl1 _App /$/ S.sepBy1 atom S.spaces1
 
 -- | An expression of our lambda calculus.
-expr :: Syntax syn Text => syn AST
-expr =  _Abs /$/ S.char '\\'   /* S.spaces_
-              */ name          /* S.spaces
-             /*  S.string "->" /* S.spaces
+--
+-- Thanks to 'tuple-morph' we don't have to worry about /* and */ here.
+-- Tuples are reassociated and units are removed by the 'morphed'
+-- isomorphism (applied in /$~ operator).
+expr :: SyntaxChar syn Text => syn AST
+expr =  _Abs /$~ S.char '\\'    /*/ S.spaces_
+             /*/ name           /*/ S.spaces
+             /*/  S.string "->" /*/ S.spaces
              /*/ expr
+
+    /|/ _Let /$~ S.string "let" /*/ S.spaces1
+             /*/ name           /*/ S.spaces
+             /*/ S.char '='     /*/ S.spaces
+             /*/ expr           /*/ S.spaces1
+             /*/ S.string "in"  /*/ S.spaces1
+             /*/ expr
+
     /|/ apps
 
 main :: IO ()
@@ -58,7 +92,7 @@
 
     -- Try to parse it.
     case AP.parseOnly (S.getParser expr <* AP.skipSpace <* AP.endOfInput) t of
-      Left err -> putStrLn err
+      Left err  -> putStrLn err
       Right ast -> do
         -- If parsing succeeded print the AST.
         print ast
@@ -66,7 +100,7 @@
         -- Try to pretty print it.
         -- (Printing cannot really fail in this example)
         case S.runPrinter expr ast of
-          Left err -> putStrLn err
+          Left err  -> putStrLn err
           Right doc -> putStrLn (P.render doc)
 
     return ()
diff --git a/syntax-example.cabal b/syntax-example.cabal
--- a/syntax-example.cabal
+++ b/syntax-example.cabal
@@ -1,6 +1,114 @@
 name:                syntax-example
-version:             0.2.0.0
+version:             0.3.0.0
 synopsis:            Example application using syntax, a library for abstract syntax descriptions.
+description:
+  Example application using syntax, a library for abstract syntax descriptions.
+  .
+  /The code./
+  .
+  > import           Control.Applicative
+  > import           Control.Lens.Cons
+  > import           Control.Lens.SemiIso
+  > import           Control.Lens.TH
+  > import qualified Data.Attoparsec.Text as AP
+  > import           Data.Char
+  > import           Data.Scientific (Scientific)
+  > import           Data.SemiIsoFunctor
+  > import           Data.Syntax (Syntax)
+  > import qualified Data.Syntax as S
+  > import qualified Data.Syntax.Attoparsec.Text as S
+  > import           Data.Syntax.Char (SyntaxChar)
+  > import qualified Data.Syntax.Char as S
+  > import qualified Data.Syntax.Combinator as S
+  > import qualified Data.Syntax.Pretty as S
+  > import           Data.Text (Text)
+  > import qualified Data.Text.IO as T
+  > import qualified Text.PrettyPrint as P
+  > 
+  > -- A simple lambda calculus.
+  > 
+  > data Literal = LitStr Text
+  >              | LitNum Scientific
+  >     deriving (Show)
+  > 
+  > $(makePrisms ''Literal)
+  > 
+  > data AST = Var Text
+  >          | Lit Literal
+  >          | App AST AST
+  >          | Abs Text AST
+  >          | Let Text AST AST
+  >     deriving (Show)
+  > 
+  > $(makePrisms ''AST)
+  > 
+  > -- | A variable name.
+  > name :: Syntax syn Text => syn Text
+  > name = _Cons /$/ S.satisfy isAlpha /*/ S.takeWhile isAlphaNum
+  > 
+  > -- | A quoted string.
+  > quoted :: SyntaxChar syn seq => syn seq
+  > quoted = S.char '"' */ S.takeTill (=='"') /* S.char '"'
+  > 
+  > -- | Encloses a symbol in parentheses.
+  > parens :: SyntaxChar syn seq => syn a -  > syn a
+  > parens m = S.char '(' */ S.spaces_ */ m /* S.spaces_ /* S.char ')'
+  > 
+  > -- | A literal.
+  > literal :: SyntaxChar syn Text => syn Literal
+  > literal =  _LitNum /$/ S.scientific
+  >        /|/ _LitStr /$/ quoted
+  > 
+  > -- | An atom is a variable, literal or an expression in parentheses.
+  > atom :: SyntaxChar syn Text => syn AST
+  > atom =  _Lit /$/ literal
+  >     /|/ _Var /$/ name
+  >     /|/ parens expr
+  > 
+  > -- | Parses a list of atoms and folds them with the _App prism.
+  > apps :: SyntaxChar syn Text => syn AST
+  > apps = bifoldl1 _App /$/ S.sepBy1 atom S.spaces1
+  > 
+  > -- | An expression of our lambda calculus.
+  > --
+  > -- Thanks to 'tuple-morph' we don't have to worry about /* and */ here.
+  > -- Tuples are reassociated and units are removed by the 'morphed'
+  > -- isomorphism (applied in /$~ operator).
+  > expr :: SyntaxChar syn Text => syn AST
+  > expr =  _Abs /$~ S.char '\\'    /*/ S.spaces_
+  >              /*/ name           /*/ S.spaces
+  >              /*/  S.string "->" /*/ S.spaces
+  >              /*/ expr
+  > 
+  >     /|/ _Let /$~ S.string "let" /*/ S.spaces1
+  >              /*/ name           /*/ S.spaces
+  >              /*/ S.char '='     /*/ S.spaces
+  >              /*/ expr           /*/ S.spaces1
+  >              /*/ S.string "in"  /*/ S.spaces1
+  >              /*/ expr
+  > 
+  >     /|/ apps
+  > 
+  > main :: IO ()
+  > main = do
+  >     -- Load the standard input.
+  >     t <- T.getContents
+  > 
+  >     -- Try to parse it.
+  >     case AP.parseOnly (S.getParser expr <* AP.skipSpace <* AP.endOfInput) t of
+  >       Left err  -> putStrLn err
+  >       Right ast -> do
+  >         -- If parsing succeeded print the AST.
+  >         print ast
+  >         
+  >         -- Try to pretty print it.
+  >         -- (Printing cannot really fail in this example)
+  >         case S.runPrinter expr ast of
+  >           Left err  -> putStrLn err
+  >           Right doc -> putStrLn (P.render doc)
+  > 
+  >     return ()
+  .
 license:             MIT
 license-file:        LICENSE
 author:              Paweł Nowak
@@ -16,7 +124,7 @@
 
 executable syntax-example
   main-is:             Main.hs
-  build-depends:       base >= 4 && < 5, lens, semi-iso >= 0.3,
-                       syntax >= 0.1.1, syntax-attoparsec, syntax-pretty,
-                       attoparsec, pretty, text
+  build-depends:       base >= 4 && < 5, lens, semi-iso >= 0.4,
+                       syntax >= 0.2, syntax-attoparsec >= 0.2, syntax-pretty >= 0.2,
+                       attoparsec, pretty, text, scientific >= 0.3
   default-language:    Haskell2010
