diff --git a/CHANGELOG.md b/CHANGELOG.md
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,6 +1,26 @@
 Changelog
 =========
 
+Version 0.1.4.0
+---------------
+
+*Mar 25, 2018*
+
+<https://github.com/mstksg/backprop/releases/tag/v0.1.4.0>
+
+*   `isoVar`, `isoVar2`, `isoVar3`, and `isoVarN`: convenient aliases for
+    applying isomorphisms to `BVar`s.  Helpful for use with constructors and
+    deconstructors.
+*   `opIso2` and `opIso3` added to *Numeric.Backprop.Op*, for convenience.
+*   `T0` (Unit with numeric instances) added to *Numeric.Backprop.Tuple".
+
+*Internal*
+
+*   Completely decoupled the internal implementation from `Num`, which showed
+    some performance benefits.  Mostly just to make the code slightly cleaner,
+    and to prepare for some day potentially decoupling the external API from
+    `Num` as well.
+
 Version 0.1.3.0
 ---------------
 
diff --git a/backprop.cabal b/backprop.cabal
--- a/backprop.cabal
+++ b/backprop.cabal
@@ -2,10 +2,10 @@
 --
 -- see: https://github.com/sol/hpack
 --
--- hash: a179c83822a97b40195355e48510d1b31057e23a68d04abb6966e24bd4b9d6f0
+-- hash: 29db4e10ba34d97fcc6fd087831de6d57d581d92e0cb33d6088380834faccda4
 
 name:           backprop
-version:        0.1.3.0
+version:        0.1.4.0
 synopsis:       Heterogeneous automatic differentation (backpropagation)
 description:    Write your functions to compute your result, and the library will
                 automatically generate functions to compute your gradient.
diff --git a/renders/backprop-mnist.pdf b/renders/backprop-mnist.pdf
Binary files a/renders/backprop-mnist.pdf and b/renders/backprop-mnist.pdf differ
diff --git a/src/Numeric/Backprop.hs b/src/Numeric/Backprop.hs
--- a/src/Numeric/Backprop.hs
+++ b/src/Numeric/Backprop.hs
@@ -61,6 +61,8 @@
   , viewVar, setVar
   , sequenceVar, collectVar
   , previewVar, toListOfVar
+    -- ** With Isomorphisms
+  , isoVar, isoVar2, isoVar3, isoVarN
     -- ** With 'Op's#liftops#
     -- $liftops
   , liftOp
@@ -369,7 +371,7 @@
 -- which do have 'Num' instances.
 --
 -- @
--- myPrism                         :: 'Prism'' c (a, b)
+-- myPrism                   :: 'Prism'' c (a, b)
 -- myPrism . 'iso' 'tupT2' 't2Tup' :: 'Prism'' c ('T2' a b)
 -- @
 (^^?)
@@ -408,3 +410,63 @@
     -> [BVar s a]
 v ^^.. t = toListOfVar t v
 {-# INLINE (^^..) #-}
+
+-- | Convert the value inside a 'BVar' using a given isomorphism.  Useful
+-- for things like constructors.
+--
+-- Warning: This is unsafe!  It assumes that the isomorphisms themselves
+-- have derivative 1, so will break for things like 'exp' & 'log'.
+-- Basically, don't use this for any "numeric" isomorphisms.
+--
+-- @since 0.1.4.0
+isoVar
+    :: (Num a, Num b, Reifies s W)
+    => (a -> b)
+    -> (b -> a)
+    -> BVar s a
+    -> BVar s b
+isoVar f g = liftOp1 (opIso f g)
+{-# INLINE isoVar #-}
+
+-- | Convert the values inside two 'BVar's using a given isomorphism.
+-- Useful for things like constructors.  See 'isoVar' for caveats.
+--
+-- @since 0.1.4.0
+isoVar2
+    :: (Num a, Num b, Num c, Reifies s W)
+    => (a -> b -> c)
+    -> (c -> (a, b))
+    -> BVar s a
+    -> BVar s b
+    -> BVar s c
+isoVar2 f g = liftOp2 (opIso2 f g)
+{-# INLINE isoVar2 #-}
+
+-- | Convert the values inside three 'BVar's using a given isomorphism.
+-- Useful for things like constructors.  See 'isoVar' for caveats.
+--
+-- @since 0.1.4.0
+isoVar3
+    :: (Num a, Num b, Num c, Num d, Reifies s W)
+    => (a -> b -> c -> d)
+    -> (d -> (a, b, c))
+    -> BVar s a
+    -> BVar s b
+    -> BVar s c
+    -> BVar s d
+isoVar3 f g = liftOp3 (opIso3 f g)
+{-# INLINE isoVar3 #-}
+
+-- | Convert the values inside a tuple of 'BVar's using a given
+-- isomorphism. Useful for things like constructors.  See 'isoVar' for
+-- caveats.
+--
+-- @since 0.1.4.0
+isoVarN
+    :: (Every Num as, Num b, Reifies s W)
+    => (Tuple as -> b)
+    -> (b -> Tuple as)
+    -> Prod (BVar s) as
+    -> BVar s b
+isoVarN f g = liftOp (opIsoN f g)
+{-# INLINE isoVarN #-}
diff --git a/src/Numeric/Backprop/Internal.hs b/src/Numeric/Backprop/Internal.hs
--- a/src/Numeric/Backprop/Internal.hs
+++ b/src/Numeric/Backprop/Internal.hs
@@ -158,10 +158,6 @@
            }
         -> SomeTapeNode
 
-forceSomeTapeNode :: SomeTapeNode -> ()
-forceSomeTapeNode (STN !_ tn) = forceTapeNode tn `seq` ()
-{-# INLINE forceSomeTapeNode #-}
-
 -- | Debugging string for a 'SomeTapeMode'.
 debugSTN :: SomeTapeNode -> String
 debugSTN (STN _ TN{..}) = show . foldMap1 ((:[]) . debugIR) $ _tnInputs
@@ -596,7 +592,6 @@
       evaluate (forceBVar oVar)
       return (_bvVal oVar)
     t <- readIORef (wRef w)
-    traverse_ (evaluate . forceSomeTapeNode) (snd t)
     return (t, o)
   where
     inpProd :: forall s. Prod (BVar s) as
diff --git a/src/Numeric/Backprop/Op.hs b/src/Numeric/Backprop/Op.hs
--- a/src/Numeric/Backprop/Op.hs
+++ b/src/Numeric/Backprop/Op.hs
@@ -47,11 +47,11 @@
   , runOp, evalOp, gradOp, gradOpWith
   -- * Creation
   , op0, opConst, idOp
-  , opConst'
+  , opConst', opLens
   -- ** Giving gradients directly
   , op1, op2, op3
   -- ** From Isomorphisms
-  , opCoerce, opTup, opIso, opIsoN, opLens
+  , opCoerce, opTup, opIso, opIso2, opIso3, opIsoN
   -- ** No gradient
   , noGrad1, noGrad
   -- * Manipulation
@@ -390,20 +390,30 @@
 -- | An 'Op' that runs the input value through an isomorphism.
 --
 -- Warning: This is unsafe!  It assumes that the isomorphisms themselves
--- have derivative 1, so will break for things like
--- 'Numeric.Lens.exponentiating'.  Basically, don't use this for any
--- "numeric" isomorphisms.
+-- have derivative 1, so will break for things like 'exp' & 'log'.
+-- Basically, don't use this for any "numeric" isomorphisms.
 opIso :: (a -> b) -> (b -> a) -> Op '[ a ] b
 opIso to' from' = op1 $ \x -> (to' x, from')
 {-# INLINE opIso #-}
 
--- | An 'Op' that runs the input value through an isomorphism between
--- a tuple of values and a value.
+-- | An 'Op' that runs the two input values through an isomorphism.  Useful
+-- for things like constructors.  See 'opIso' for caveats.
 --
--- Warning: This is unsafe!  It assumes that the isomorphisms themselves
--- have derivative 1, so will break for things like
--- 'Numeric.Lens.exponentiating'.  Basically, don't use this for any
--- "numeric" isomorphisms.
+-- @since 0.1.4.0
+opIso2 :: (a -> b -> c) -> (c -> (a, b)) -> Op '[a, b] c
+opIso2 to' from' = op2 $ \x y -> (to' x y, from')
+{-# INLINE opIso2 #-}
+
+-- | An 'Op' that runs the three input values through an isomorphism.
+-- Useful for things like constructors.  See 'opIso' for caveats.
+--
+-- @since 0.1.4.0
+opIso3 :: (a -> b -> c -> d) -> (d -> (a, b, c)) -> Op '[a, b, c] d
+opIso3 to' from' = op3 $ \x y z -> (to' x y z, from')
+{-# INLINE opIso3 #-}
+
+-- | An 'Op' that runs the input value through an isomorphism between
+-- a tuple of values and a value.  See 'opIso' for caveats.
 --
 -- In "Numeric.Backprop.Op" since version 0.1.2.0, but only exported from
 -- "Numeric.Backprop" since version 0.1.3.0.
diff --git a/src/Numeric/Backprop/Tuple.hs b/src/Numeric/Backprop/Tuple.hs
--- a/src/Numeric/Backprop/Tuple.hs
+++ b/src/Numeric/Backprop/Tuple.hs
@@ -13,9 +13,9 @@
 -- Stability   : experimental
 -- Portability : non-portable
 --
--- Canonical strict tuples with 'Num' instances for usage with /backprop/.
--- This is here to solve the problem of orphan instances in libraries and
--- potential mismatched tuple types.
+-- Canonical strict tuples (and unit) with 'Num' instances for usage with
+-- /backprop/. This is here to solve the problem of orphan instances in
+-- libraries and potential mismatched tuple types.
 --
 -- If you are writing a library that needs to export 'BVar's of tuples,
 -- consider using the tuples in this module so that your library can have
@@ -47,13 +47,18 @@
 -- and '_3' from "Lens.Micro".  However, note that these are incompatible
 -- with '_1', '_2', and '_3' from "Control.Lens".
 --
+-- You can "construct" a @'BVar' s ('T2' a b)@ with functions like
+-- 'isoVar'.
+--
 -- @since 0.1.1.0
 --
 
 
 module Numeric.Backprop.Tuple (
+  -- * Zero-tuples (unit)
+    T0(..)
   -- * Two-tuples
-    T2(..)
+  , T2(..)
   -- ** Conversions
   -- $t2iso
   , t2Tup, tupT2
@@ -80,13 +85,29 @@
 import           Lens.Micro
 import           Lens.Micro.Internal
 
--- | Strict 2-tuple with a 'Num' instance.
+-- | Unit ('()') with 'Num', 'Fractional', and 'Floating' instances.
 --
+-- Be aware that the methods in its numerical instances are all non-strict:
+--
+-- @@
+-- _ + _ = 'T0'
+-- 'negate' _ = 'T0'
+-- 'fromIntegral' _ = 'T0'
+-- @@
+--
+-- @since 0.1.4.0
+data T0 = T0
+  deriving (Show, Read, Eq, Ord, Generic, Data)
+
+instance NFData T0
+
+-- | Strict 2-tuple with 'Num', 'Fractional', and 'Floating' instances.
+--
 -- @since 0.1.1.0
 data T2 a b   = T2 !a !b
   deriving (Show, Read, Eq, Ord, Generic, Functor, Data)
 
--- | Strict 3-tuple with a 'Num' instance.
+-- | Strict 3-tuple with a 'Num', 'Fractional', and 'Floating' instances.
 --
 -- @since 0.1.1.0
 data T3 a b c = T3 !a !b !c
@@ -188,6 +209,38 @@
 -- "Lens.Micro".
 t3_3 :: Lens (T3 a b c) (T3 a b c') c c'
 t3_3 = _3
+
+instance Num T0 where
+    _ + _         = T0
+    _ - _         = T0
+    _ * _         = T0
+    negate _      = T0
+    abs    _      = T0
+    signum _      = T0
+    fromInteger _ = T0
+
+instance Fractional T0 where
+    _ / _          = T0
+    recip _        = T0
+    fromRational _ = T0
+
+instance Floating T0 where
+    pi          = T0
+    _ ** _      = T0
+    logBase _ _ = T0
+    exp   _     = T0
+    log   _     = T0
+    sqrt  _     = T0
+    sin   _     = T0
+    cos   _     = T0
+    asin  _     = T0
+    acos  _     = T0
+    atan  _     = T0
+    sinh  _     = T0
+    cosh  _     = T0
+    asinh _     = T0
+    acosh _     = T0
+    atanh _     = T0
 
 instance (Num a, Num b) => Num (T2 a b) where
     T2 x1 y1 + T2 x2 y2 = T2 (x1 + x2) (y1 + y2)
