diff --git a/ginger.cabal b/ginger.cabal
--- a/ginger.cabal
+++ b/ginger.cabal
@@ -2,7 +2,7 @@
 -- documentation, see http://haskell.org/cabal/users-guide/
 
 name:                ginger
-version:             0.2.2.0
+version:             0.2.3.0
 synopsis:            An implementation of the Jinja2 template language in Haskell
 description:         Ginger is Jinja, minus the most blatant pythonisms. Wants
                      to be feature complete, but isn't quite there yet.
diff --git a/src/Text/Ginger/AST.hs b/src/Text/Ginger/AST.hs
--- a/src/Text/Ginger/AST.hs
+++ b/src/Text/Ginger/AST.hs
@@ -58,4 +58,5 @@
     | ObjectE [(Expression, Expression)] -- ^ Object construct: { expr: expr, expr: expr, ... }
     | MemberLookupE Expression Expression -- ^ foo[bar] (also dot access)
     | CallE Expression [(Maybe Text, Expression)] -- ^ foo(bar=baz, quux)
+    | LambdaE [Text] Expression -- ^ (foo, bar) -> expr
     deriving (Show)
diff --git a/src/Text/Ginger/GVal.hs b/src/Text/Ginger/GVal.hs
--- a/src/Text/Ginger/GVal.hs
+++ b/src/Text/Ginger/GVal.hs
@@ -58,6 +58,7 @@
 import Control.Monad.Trans (MonadTrans, lift)
 import Data.Default (Default, def)
 import Text.Printf
+import Debug.Trace (trace)
 
 import Text.Ginger.Html
 
@@ -110,7 +111,10 @@
     show v
         | isNull v = "null"
         | isJust (asFunction v) = "<<function>>"
-        | isJust (asDictItems v) = "{" <> (mconcat . List.intersperse ", " $ [ show k <> ": " <> show v | (k, v) <- fromMaybe [] (asDictItems v) ]) <> "}"
+        | isJust (asDictItems v) =
+            let items = [ show k <> ": " <> show v | (k, v) <- fromMaybe [] (asDictItems v) ]
+                      ++ [ show k <> ": " <> show v | (k, v) <- Prelude.zip [0..] (fromMaybe [] $ asList v) ]
+            in "{" <> (mconcat . List.intersperse ", " $ items) <> "}"
         | isJust (asList v) = "[" <> (mconcat . List.intersperse ", " . Prelude.map show $ fromMaybe [] (asList v)) <> "]"
         | isJust (asNumber v) =
             case floatingOrInteger <$> asNumber v :: Maybe (Either Double Integer) of
@@ -133,9 +137,9 @@
             'c' -> formatString
                     (Text.unpack $ asText x)
                     fmt
-            _ -> formatRealFloat
-                    (toRealFloat . fromMaybe 0 . asNumber $ x :: Double)
-                    fmt
+            f -> if f `Prelude.elem` ("fFgGeE" :: [Char])
+                    then formatRealFloat (toRealFloat . fromMaybe 0 . asNumber $ x) fmt
+                    else formatInteger (Prelude.round . fromMaybe 0 . asNumber $ x) fmt
 
 -- * Representing functions as 'GVal's
 --
diff --git a/src/Text/Ginger/Parse.hs b/src/Text/Ginger/Parse.hs
--- a/src/Text/Ginger/Parse.hs
+++ b/src/Text/Ginger/Parse.hs
@@ -438,7 +438,21 @@
     optional . ignore . char $ '\n'
 
 expressionP :: Monad m => Parser m Expression
-expressionP = booleanExprP
+expressionP = lambdaExprP <|> booleanExprP
+
+lambdaExprP :: Monad m => Parser m Expression
+lambdaExprP = do
+    argNames <- try $ do
+        char '('
+        spaces
+        argNames <- sepBy (spaces >> identifierP) (try $ spaces >> char ',')
+        char ')'
+        spaces
+        string "->"
+        spaces
+        return argNames
+    body <- expressionP
+    return $ LambdaE argNames body
 
 operativeExprP :: forall m. Monad m => Parser m Expression -> [ (String, Text) ] -> Parser m Expression
 operativeExprP operandP operators = do
diff --git a/src/Text/Ginger/Run.hs b/src/Text/Ginger/Run.hs
--- a/src/Text/Ginger/Run.hs
+++ b/src/Text/Ginger/Run.hs
@@ -159,6 +159,7 @@
             , ("escape", fromFunction gfnEscape)
             , ("e", fromFunction gfnEscape)
             , ("filesizeformat", fromFunction gfnFileSizeFormat)
+            , ("filter", fromFunction gfnFilter)
             , ("equals", fromFunction gfnEquals)
             , ("nequals", fromFunction gfnNEquals)
             , ("greaterEquals", fromFunction gfnGreaterEquals)
@@ -453,13 +454,18 @@
             where
                 fmtStr = Text.unpack $ asText fmtStrG
 
-printfG :: String -> [GVal m] -> String
-printfG fmt args = printfa fmt (fmap (P . asText) args)
+        gfnFilter :: Function (Run m h)
+        gfnFilter [] = return def
+        gfnFilter [(_, xs)] = return xs
+        gfnFilter ((_, xs):(_, p):args) = do
+            pfnG <- maybe (fail "Not a function") return (asFunction p)
+            let pfn x = asBoolean <$> pfnG ((Nothing, x):args)
+                xsl = fromMaybe [] (asList xs)
+            filtered <- filterM pfn xsl
+            return $ toGVal filtered
 
-apply :: (a -> b -> b) -> b -> [a] -> b
-apply f z [] = z
-apply f z [x] = f x z
-apply f z (x:xs) = f x (apply f z xs)
+printfG :: String -> [GVal m] -> String
+printfG fmt args = printfa fmt (fmap P args)
 
 -- | Create an execution context for runGingerT.
 -- Takes a lookup function, which returns ginger values into the carrier monad
@@ -742,6 +748,12 @@
     case func of
         Nothing -> return def
         Just f -> f args
+runExpression (LambdaE argNames body) = do
+    let fn args = withLocalScope $ do
+            forM (Prelude.zip argNames (fmap snd args)) $ \(argName, arg) ->
+                setVar argName arg
+            runExpression body
+    return $ fromFunction fn
 
 -- | Helper function to output a HTML value using whatever print function the
 -- context provides.
