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.5.2.1
+version:             0.5.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.
@@ -50,7 +50,6 @@
                , unordered-containers >= 0.2.5
                , utf8-string
                , vector
-               , wryte
   hs-source-dirs:      src
   default-language:    Haskell2010
 
@@ -66,7 +65,6 @@
                  , text
                  , transformers
                  , unordered-containers >= 0.2.5
-                 , wryte
 
 test-suite tests
     type: exitcode-stdio-1.0
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
@@ -2,6 +2,7 @@
 {-#LANGUAGE MultiParamTypeClasses #-}
 {-#LANGUAGE FlexibleInstances #-}
 {-#LANGUAGE ScopedTypeVariables #-}
+{-#LANGUAGE RankNTypes #-}
 
 -- | GVal is a generic unitype value, representing the kind of values that
 -- Ginger can understand.
@@ -34,6 +35,7 @@
                , not
                , fst, snd
                , Monad
+               , Functor
                )
 import qualified Prelude
 import Data.Maybe ( fromMaybe, catMaybes, isJust, mapMaybe )
@@ -127,6 +129,39 @@
         , length = length g
         , asJSON = asJSON g
         }
+
+-- | Marshal a GVal between carrier monads.
+-- Unlike 'marshalGVal', 'asFunction' information is retained by hoisting
+-- them using the provided hoisting functions. For 'Run' monads, which is
+-- what 'GVal' is typically used with, the 'hoistRun' function can be used
+-- to construct suitable hoisting functions.
+marshalGValEx :: (Functor m, Functor n)
+              => (forall a. m a -> n a)
+              -> (forall a. n a -> m a)
+              -> GVal m
+              -> GVal n
+marshalGValEx hoist unhoist g =
+    GVal
+        { asList = fmap (marshalGValEx hoist unhoist) <$> asList g
+        , asDictItems = fmap (\items -> [(k, marshalGValEx hoist unhoist v) | (k, v) <- items]) (asDictItems g)
+        , asLookup = fmap (fmap (marshalGValEx hoist unhoist) .) (asLookup g)
+        , asHtml = asHtml g
+        , asText = asText g
+        , asBoolean = asBoolean g
+        , asNumber = asNumber g
+        , asFunction = marshalFunction hoist unhoist <$> asFunction g
+        , isNull = isNull g
+        , length = length g
+        , asJSON = asJSON g
+        }
+
+marshalFunction :: (Functor m, Functor n) => (forall a. m a -> n a) -> (forall a. n a -> m a) -> Function m -> Function n
+-- [(Maybe Text, GVal m)] -> m (GVal m)
+marshalFunction hoist unhoist f args =
+    let args' = [ (name, marshalGValEx unhoist hoist value)
+                | (name, value) <- args
+                ]
+    in marshalGValEx hoist unhoist <$> hoist (f args')
 
 -- | Convenience wrapper around 'asDictItems' to represent a 'GVal' as a
 -- 'HashMap'.
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
@@ -46,6 +46,11 @@
 , Run, liftRun, liftRun2
 -- * Helper functions for interpreting argument lists
 , extractArgs, extractArgsT, extractArgsL, extractArgsDefL
+-- * Hoisting
+, hoistContext
+, hoistRun
+, hoistNewlines
+, hoistRunState
 )
 where
 
diff --git a/src/Text/Ginger/Run/Type.hs b/src/Text/Ginger/Run/Type.hs
--- a/src/Text/Ginger/Run/Type.hs
+++ b/src/Text/Ginger/Run/Type.hs
@@ -24,6 +24,11 @@
 -- * The Newlines type
 -- | Required for handling indentation
 , Newlines (..)
+-- * Hoisting
+, hoistContext
+, hoistRun
+, hoistNewlines
+, hoistRunState
 )
 where
 
@@ -89,6 +94,29 @@
         , contextNewlines :: Maybe (Newlines h)
         }
 
+-- | Hoist a context onto a different output type.
+-- @hoistContext fwd rev context@ returns a context over a different
+-- output type, applying the @fwd@ and @rev@ projections to convert
+-- between the original and desired output types.
+hoistContext :: Monad m => (h -> t) -> (t -> h) -> GingerContext m h -> GingerContext m t
+hoistContext fwd rev c =
+    GingerContext
+        { contextLookup = \varName ->
+            marshalGValEx
+                (hoistRun fwd rev)
+                (hoistRun rev fwd) <$>
+                hoistRun fwd rev (contextLookup c varName)
+        , contextWrite = \val ->
+            hoistRun fwd rev (contextWrite c $ rev val)
+        , contextEncode = \gval ->
+            fwd .
+                contextEncode c .
+                marshalGValEx (hoistRun rev fwd) (hoistRun fwd rev) $
+                gval
+        , contextNewlines =
+            hoistNewlines fwd rev <$> contextNewlines c
+        }
+
 contextWriteEncoded :: GingerContext m h -> GVal (Run m h) -> Run m h ()
 contextWriteEncoded context =
     contextWrite context . contextEncode context
@@ -213,6 +241,18 @@
         , endsWithNewline :: h -> Bool
         }
 
+-- | Hoist a 'Newlines' onto a different output type.
+-- You don't normally need to use this directly; see 'hoistRun' and/or
+-- 'hoistContext'.
+hoistNewlines :: (h -> t) -> (t -> h) -> Newlines h -> Newlines t
+hoistNewlines fwd rev n =
+    Newlines
+        { splitLines = List.map fwd . splitLines n . rev
+        , joinLines = fwd . joinLines n . List.map rev
+        , stripIndent = fwd . stripIndent n . rev
+        , endsWithNewline = endsWithNewline n . rev
+        }
+
 textNewlines :: Newlines Text
 textNewlines =
     Newlines
@@ -249,6 +289,20 @@
         , rsAtLineStart :: Bool -- is the next output position the first column
         }
 
+-- | Hoist a 'RunState' onto a different output type.
+-- You don't normally need to use this directly; see 'hoistRun' and/or
+-- 'hoistContext'.
+hoistRunState :: Monad m => (h -> t) -> (t -> h) -> RunState m h -> RunState m t
+hoistRunState fwd rev rs =
+    RunState
+        { rsScope = marshalGValEx (hoistRun fwd rev) (hoistRun rev fwd) <$> rsScope rs
+        , rsCapture = fwd $ rsCapture rs
+        , rsCurrentTemplate = rsCurrentTemplate rs
+        , rsCurrentBlockName = rsCurrentBlockName rs
+        , rsIndentation = fmap fwd <$> rsIndentation rs
+        , rsAtLineStart = rsAtLineStart rs
+        }
+
 -- | Internal type alias for our template-runner monad stack.
 type Run m h = StateT (RunState m h) (ReaderT (GingerContext m h) m)
 
@@ -259,3 +313,18 @@
 -- | Lift a function from the host monad @m@ into the 'Run' monad.
 liftRun2 :: Monad m => (a -> m b) -> a -> Run m h b
 liftRun2 f x = liftRun $ f x
+
+-- | Hoist a 'Run' action onto a different output type.
+-- @hoistRun fwd rev action@ hoists the @action@ from @Run m h a@ to
+-- @Run m t a@, applying @fwd@ and @rev@ to convert between the output
+-- types.
+hoistRun :: Monad m => (h -> t) -> (t -> h) -> Run m h a -> Run m t a
+hoistRun fwd rev action = do
+    contextT <- ask
+    let contextH = hoistContext rev fwd contextT
+    stateT <- get
+    let stateH = hoistRunState rev fwd stateT
+    (x, stateH') <- lift . lift $ runReaderT (runStateT action stateH) contextH
+    let stateT' = hoistRunState fwd rev stateH'
+    put stateT'
+    return x
diff --git a/src/Text/Ginger/Run/VM.hs b/src/Text/Ginger/Run/VM.hs
--- a/src/Text/Ginger/Run/VM.hs
+++ b/src/Text/Ginger/Run/VM.hs
@@ -7,7 +7,7 @@
 import Text.Ginger.GVal
 import Data.Monoid ( (<>) )
 import Control.Monad.State (MonadState (..), get, gets, modify)
-import Control.Monad.Reader (asks)
+import Control.Monad.Reader (asks, local)
 import qualified Data.HashMap.Strict as HashMap
 import Data.HashMap.Strict (HashMap)
 
@@ -28,6 +28,12 @@
     r <- a
     modify (\s -> s { rsScope = scope })
     return r
+
+-- | Override the encoder used for converting 'GVal's to the output type.
+-- This can be used for things like temporarily disabling HTML encoding.
+withEncoder :: (ContextEncodable h, Monad m) => (GVal (Run m h) -> h) -> Run m h a -> Run m h a
+withEncoder encoder =
+    local (\context -> context { contextEncode = encode })
 
 setVar :: Monad m => VarName -> GVal (Run m h) -> Run m h ()
 setVar name val = do
