diff --git a/Text/Shakespeare.hs b/Text/Shakespeare.hs
--- a/Text/Shakespeare.hs
+++ b/Text/Shakespeare.hs
@@ -29,8 +29,8 @@
 import Text.Shakespeare.Base
 
 -- move to Shakespeare?
-readFileQ :: FilePath -> Q [Char]
-readFileQ fp = do
+readFileQ :: FilePath -> Q String
+readFileQ fp =
     qRunIO $ readFileUtf8 fp
 
 -- move to Shakespeare?
@@ -86,7 +86,7 @@
 type Contents = [Content]
 
 contentFromString :: ShakespeareSettings -> (String -> [Content])
-contentFromString rs s = do
+contentFromString rs s =
     compressContents $ either (error . show) id $ parse (parseContents rs) s s
   where
     compressContents :: Contents -> Contents
@@ -109,7 +109,7 @@
             go (d, False) = ContentUrl d
             go (d, True) = ContentUrlParam d
         parseCaret' = either ContentRaw ContentMix `fmap` parseInt intChar
-        parseChar = ContentRaw `fmap` (many1 $ noneOf [varChar, urlChar, intChar])
+        parseChar = ContentRaw `fmap` many1 (noneOf [varChar, urlChar, intChar])
 
 contentsToShakespeare :: ShakespeareSettings -> [Content] -> Q Exp
 contentsToShakespeare rs a = do
@@ -128,16 +128,16 @@
         contentToBuilder :: Name -> Content -> Q Exp
         contentToBuilder _ (ContentRaw s') = do
             ts <- [|fromText . TS.pack|]
-            return $ (wrap rs) `AppE` (ts `AppE` LitE (StringL s'))
+            return $ wrap rs `AppE` (ts `AppE` LitE (StringL s'))
         contentToBuilder _ (ContentVar d) = do
-            return $ (wrap rs) `AppE` ((toBuilder rs) `AppE` derefToExp [] d)
+            return $ wrap rs `AppE` (toBuilder rs `AppE` derefToExp [] d)
         contentToBuilder r (ContentUrl d) = do
             ts <- [|fromText|]
-            return $ (wrap rs) `AppE` (ts `AppE` (VarE r `AppE` derefToExp [] d `AppE` ListE []))
+            return $ wrap rs `AppE` (ts `AppE` (VarE r `AppE` derefToExp [] d `AppE` ListE []))
         contentToBuilder r (ContentUrlParam d) = do
             ts <- [|fromText|]
             up <- [|\r' (u, p) -> r' u p|]
-            return $ (wrap rs) `AppE` (ts `AppE` (up `AppE` VarE r `AppE` derefToExp [] d))
+            return $ wrap rs `AppE` (ts `AppE` (up `AppE` VarE r `AppE` derefToExp [] d))
         contentToBuilder r (ContentMix d) = do
             return $ derefToExp [] d `AppE` VarE r
 
diff --git a/Text/Shakespeare/Base.hs b/Text/Shakespeare/Base.hs
--- a/Text/Shakespeare/Base.hs
+++ b/Text/Shakespeare/Base.hs
@@ -22,7 +22,7 @@
 
 import Language.Haskell.TH.Syntax
 import Language.Haskell.TH (appE)
-import Data.Char (isUpper)
+import Data.Char (isUpper, isSymbol)
 import Text.ParserCombinators.Parsec
 import Data.List (intercalate)
 import Data.Ratio (Ratio, numerator, denominator, (%))
@@ -31,6 +31,7 @@
 import qualified Data.Text.Lazy as TL
 import qualified System.IO as SIO
 import qualified Data.Text.Lazy.IO as TIO
+import Control.Monad (when)
 
 newtype Ident = Ident String
     deriving (Show, Eq, Read, Data, Typeable)
@@ -43,6 +44,7 @@
            | DerefRational Rational
            | DerefString String
            | DerefBranch Deref Deref
+           | DerefList [Deref]
     deriving (Show, Eq, Read, Data, Typeable)
 
 instance Lift Ident where
@@ -68,16 +70,24 @@
         d <- lift $ denominator r
         per <- [|(%) :: Int -> Int -> Ratio Int|]
         dr <- [|DerefRational|]
-        return $ dr `AppE` (InfixE (Just n) per (Just d))
+        return $ dr `AppE` InfixE (Just n) per (Just d)
     lift (DerefString s) = [|DerefString|] `appE` lift s
+    lift (DerefList x) = [|DerefList $(lift x)|]
 
+derefParens, derefCurlyBrackets :: Parser Deref
+derefParens        = between (char '(') (char ')') parseDeref
+derefCurlyBrackets = between (char '{') (char '}') parseDeref
+
+derefList :: Parser Deref
+derefList = between (char '[') (char ']') (fmap DerefList $ sepBy parseDeref (char ','))
+
 parseDeref :: Parser Deref
-parseDeref = do
-    skipMany $ oneOf " \t"
+parseDeref = skipMany (oneOf " \t") >> (derefList <|> (do
     x <- derefSingle
-    res <- deref' $ (:) x
-    skipMany $ oneOf " \t"
-    return res
+    (derefInfix x) <|> (do
+        res <- deref' $ (:) x
+        skipMany $ oneOf " \t"
+        return res)))
   where
     delim = (many1 (char ' ') >> return())
             <|> lookAhead (oneOf "(\"" >> return ())
@@ -86,7 +96,15 @@
         x <- many1 $ noneOf " \t\n\r()"
         _ <- char ')'
         return $ DerefIdent $ Ident x
-    derefParens = between (char '(') (char ')') parseDeref
+    derefInfix x = try $ do
+        _ <- many1 $ oneOf " \t"
+        op <- many1 (satisfy $ \c -> isSymbol c || c `elem` "-") <?> "operator"
+        -- special handling for $, which we don't deal with
+        when (op == "$") $ fail "don't handle $"
+        let op' = DerefIdent $ Ident op
+        _ <- many1 (oneOf " \t")
+        y <- derefSingle
+        return $ DerefBranch (DerefBranch op' x) y
     derefSingle = derefOp <|> derefParens <|> numeric <|> strLit<|> ident
     deref' lhs =
         dollar <|> derefSingle'
@@ -115,13 +133,9 @@
         return $ DerefString chars
     quotedChar = (char '\\' >> escapedChar) <|> noneOf "\""
     escapedChar =
-        (char 'n' >> return '\n') <|>
-        (char 'r' >> return '\r') <|>
-        (char 'b' >> return '\b') <|>
-        (char 't' >> return '\t') <|>
-        (char '\\' >> return '\\') <|>
-        (char '"' >> return '"') <|>
-        (char '\'' >> return '\'')
+        let cecs = [('n', '\n'),  ('r', '\r'), ('b', '\b'), ('t', '\t')
+                   ,('\\', '\\'), ('"', '"'),  ('\'', '\'')]
+        in choice [ char c >> return ec | (c, ec) <- cecs]
     ident = do
         mods <- many modul
         func <- many1 (alphaNum <|> char '_' <|> char '\'')
@@ -157,6 +171,7 @@
 derefToExp _ (DerefIntegral i) = LitE $ IntegerL i
 derefToExp _ (DerefRational r) = LitE $ RationalL r
 derefToExp _ (DerefString s) = LitE $ StringL s
+derefToExp s (DerefList ds) = ListE $ map (derefToExp s) ds
 
 -- FIXME shouldn't we use something besides a list here?
 flattenDeref :: Deref -> Maybe [String]
@@ -173,9 +188,7 @@
 parseVar c = do
     _ <- char c
     (char '\\' >> return (Left [c])) <|> (do
-        _ <- char '{'
-        deref <- parseDeref
-        _ <- char '}'
+        deref <- derefCurlyBrackets
         return $ Right deref) <|> (do
             -- Check for hash just before newline
             _ <- lookAhead (oneOf "\r\n" >> return ()) <|> eof
@@ -191,9 +204,7 @@
     (char '\\' >> return (Left [c])) <|> (do
         x <- (char d >> return True) <|> return False
         (do
-            _ <- char '{'
-            deref <- parseDeref
-            _ <- char '}'
+            deref <- derefCurlyBrackets
             return $ Right (deref, x))
                 <|> return (Left $ if x then [c, d] else [c]))
 
@@ -204,18 +215,14 @@
 parseInt c = do
     _ <- char c
     (char '\\' >> return (Left [c])) <|> (do
-        _ <- char '{'
-        deref <- parseDeref
-        _ <- char '}'
+        deref <- derefCurlyBrackets
         return $ Right deref) <|> return (Left [c])
 
 parseUnder :: Parser (Either String Deref)
 parseUnder = do
     _ <- char '_'
     (char '\\' >> return (Left "_")) <|> (do
-        _ <- char '{'
-        deref <- parseDeref
-        _ <- char '}'
+        deref <- derefCurlyBrackets
         return $ Right deref) <|> return (Left "_")
 
 readUtf8File :: FilePath -> IO TL.Text
diff --git a/shakespeare.cabal b/shakespeare.cabal
--- a/shakespeare.cabal
+++ b/shakespeare.cabal
@@ -1,5 +1,5 @@
 name:            shakespeare
-version:         0.10.1.1
+version:         0.10.2
 license:         BSD3
 license-file:    LICENSE
 author:          Michael Snoyman <michael@snoyman.com>
