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.8.0.1
+version:             0.8.1.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/Run.hs b/src/Text/Ginger/Run.hs
--- a/src/Text/Ginger/Run.hs
+++ b/src/Text/Ginger/Run.hs
@@ -129,6 +129,7 @@
     , ("capitalize", fromFunction . variadicStringFunc $ mconcat . Prelude.map capitalize)
     , ("ceil", fromFunction . unaryNumericFunc 0 $ Prelude.fromIntegral . Prelude.ceiling)
     , ("center", fromFunction gfnCenter)
+    , ("compose", fromFunction gfnCompose)
     , ("concat", fromFunction gfnConcat)
     , ("contains", fromFunction gfnContains)
     , ("d", fromFunction gfnDefault)
@@ -171,6 +172,7 @@
     , ("nequals", fromFunction gfnNEquals)
     , ("num", fromFunction . unaryFunc $ toGVal . asNumber)
     , ("odd", fromFunction gfnOdd)
+    , ("partial", fromFunction gfnPartial)
     , ("printf", fromFunction gfnPrintf)
     , ("product", fromFunction . variadicNumericFunc 1 $ Prelude.product)
     , ("ratio", fromFunction . variadicNumericFunc 1 $ Scientific.fromFloatDigits . ratio . Prelude.map Scientific.toRealFloat)
@@ -186,6 +188,8 @@
     , ("upper", fromFunction . variadicStringFunc $ mconcat . Prelude.map Text.toUpper)
     , ("lower", fromFunction . variadicStringFunc $ mconcat . Prelude.map Text.toLower)
     , ("throw", fromFunction gfnThrow)
+    , ("zip", fromFunction gfnZip)
+    , ("zipwith", fromFunction gfnZipWith)
 
     -- Tests/predicates
 
diff --git a/src/Text/Ginger/Run/Builtins.hs b/src/Text/Ginger/Run/Builtins.hs
--- a/src/Text/Ginger/Run/Builtins.hs
+++ b/src/Text/Ginger/Run/Builtins.hs
@@ -309,6 +309,67 @@
             return . toGVal $ Text.replace search replace str
         _ -> throwHere $ ArgumentsError (Just "replace") "expected: (str, search, replace)"
 
+gfnCompose :: forall m p h. Monad m => Function (Run p m h)
+gfnCompose [] = fail "Invalid arguments to compose()"
+gfnCompose [(_, fG)] = return fG
+gfnCompose ((_, fG):xs) = do
+  gG <- gfnCompose xs
+  case (asFunction fG, asFunction gG) of
+    (Nothing, _) -> fail $ "Argument to compose() is not a function"
+    (_, Nothing) -> fail $ "PANIC: Composition of functions is not a function"
+    (Just f, Just g) -> do
+      let h args = do
+              arg' <- g args
+              f [(Nothing, arg')]
+      return $ fromFunction h
+
+gfnPartial :: forall m p h. Monad m => Function (Run p m h)
+gfnPartial [] = fail "Invalid arguments to partial()"
+gfnPartial ((_, fG):args) = do
+  case asFunction fG of
+    Nothing -> fail "Argument to partial() is not a function"
+    Just f -> do
+      let h args' = do
+            f (args ++ args')
+      return $ fromFunction h
+
+gfnZip :: forall m p h. Monad m => Function (Run p m h)
+gfnZip args = do
+  toGVal <$> go (fmap (fromMaybe [] . asList . snd) args)
+  where
+    go :: [[GVal (Run p m h)]] -> Run p m h [GVal (Run p m h)]
+    go [] = return []
+    go args = do
+      let heads = fmap headMay args
+          tails = fmap (List.drop 1) args
+      if List.any isNothing heads then
+        return []
+      else do
+        let currentVal = toGVal (fmap (fromMaybe def) heads)
+        tailVals <- go tails
+        return $ currentVal : tailVals
+
+
+gfnZipWith :: forall m p h. Monad m => Function (Run p m h)
+gfnZipWith ((Nothing, gfn):args) = do
+  zipFunction <- case asFunction gfn of
+    Nothing -> fail $ "Invalid args to zipwith"
+    Just fn -> return fn
+  toGVal <$> go zipFunction (fmap fst args) (fmap (fromMaybe [] . asList . snd) args)
+  where
+    go :: Function (Run p m h) -> [Maybe Text] -> [[GVal (Run p m h)]] -> Run p m h [GVal (Run p m h)]
+    go f _ [] = return []
+    go f argNames args = do
+      let heads = fmap headMay args
+          tails = fmap (List.drop 1) args
+      if List.any isNothing heads then
+        return []
+      else do
+        currentVal <- f (List.zip argNames (fmap (fromMaybe def) heads))
+        tailVals <- go f argNames tails
+        return $ currentVal : tailVals
+
+
 gfnMap :: Monad m => Function m
 gfnMap args = do
     let parsedArgs = extractArgsDefL
diff --git a/test/Text/Ginger/SimulationTests.hs b/test/Text/Ginger/SimulationTests.hs
--- a/test/Text/Ginger/SimulationTests.hs
+++ b/test/Text/Ginger/SimulationTests.hs
@@ -497,6 +497,10 @@
                     "{{ \"foobar\"|center(2) }}"
                     "foobar"
             ]
+        , testCase "\"compose\"" $ do
+            mkTestText [] []
+                "{{ (compose(json, capitalize))('hello') }}"
+                "\"Hello\""
         , testCase "\"concat\"" $ do
             mkTestHtml [] []
                 "{{ [\"hello\", \"world\"]|concat }}"
@@ -747,7 +751,12 @@
         -- \"modulo\"
         -- \"num\"
         -- TODO
-        -- \"printf\"
+        , testGroup "\"partial\""
+            [ testCase "partial" $ do
+                mkTestHtml [] []
+                  "{{ partial(sum, 1)(2) }}"
+                  "3"
+            ]
         , testGroup "\"printf\""
             [ testCase "%i, passed as int" $ do
                 mkTestHtml [] []
@@ -901,6 +910,18 @@
                 mkTestHtml [] []
                     "{{ replace('foobar', 'o') }}"
                     "fbar"
+            ]
+        , testGroup "\"zip\""
+            [ testCase "lists" $ do
+                mkTestHtml [] []
+                    "{{ zip([1,2,3], [4,5,6])|json(pretty=false) }}"
+                    "[[1,4],[2,5],[3,6]]"
+            ]
+        , testGroup "\"zipwith\""
+            [ testCase "sum" $ do
+                mkTestHtml [] []
+                    "{{ zipwith(sum, [1,2,3], [4,5,6])|json(pretty=false) }}"
+                    "[5,7,9]"
             ]
         , testGroup "\"json\""
             [ testCase "null" $ do
