diff --git a/CHANGELOG.md b/CHANGELOG.md
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,6 +1,33 @@
 Changelog
 =========
 
+Version 0.2.2.0
+---------------
+
+*May 12, 2018*
+
+<https://github.com/mstksg/backprop/releases/tag/v0.2.2.0>
+
+*   `evalBP0` added, for convenience for no-argument values that need to be
+    evaluated without backpropagation.
+*   `splitBV` and `joinBV` for "higher-kinded data" style `BVar` manipulation,
+    via the `BVGroup` helper typeclass.
+*   `toList`, `mapAccumL`, and `mapAccumR` for *Prelude.Backprop* modules
+*   `Backprop` instance for `BVar`
+*   *COMPLETE* pragmas for `T2` and `T3`
+*   Un-exported `gzero`, `gadd`, and `gone` from *Numeric.Backprop.Class*
+*   Many, many more instances of `Backprop`
+*   `Backprop` instance for `Proxy` made non-strict for `add`
+*   Swapped type variable order for a few library functions, which might
+    potentially be breaking changes.
+
+*Internal*
+
+*   Fixed documentation for Num and Explicit Prelude modules, and rewrote
+    normal and Num Prelude modules in terms of canonical Prelude definitions
+*   Switched to `errorWithoutStackTrace` wherever appropriate (in *Internal*
+    module)
+
 Version 0.2.1.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: 2877842d9cf55116566216ea0e7a25477c1df3557ff9e0d96a97d815dc772ac8
+-- hash: d347cf6994856b821bb3cf3172a4b5ec8f0d39b680e29e39a019d89cf022b2a5
 
 name:           backprop
-version:        0.2.1.0
+version:        0.2.2.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.
@@ -43,7 +43,7 @@
 library
   hs-source-dirs:
       src
-  ghc-options: -Wall -Wcompat -Wincomplete-record-updates -Wredundant-constraints -fprint-explicit-kinds
+  ghc-options: -Wall -Wcompat -Wincomplete-record-updates -Wredundant-constraints
   build-depends:
       base >=4.7 && <5
     , containers
@@ -73,7 +73,7 @@
   main-is: bench.hs
   hs-source-dirs:
       bench
-  ghc-options: -Wall -Wcompat -Wincomplete-record-updates -Wredundant-constraints -fprint-explicit-kinds -threaded -rtsopts -with-rtsopts=-N -O2
+  ghc-options: -Wall -Wcompat -Wincomplete-record-updates -Wredundant-constraints -threaded -rtsopts -with-rtsopts=-N -O2
   build-depends:
       backprop
     , base >=4.7 && <5
diff --git a/src/Data/Type/Util.hs b/src/Data/Type/Util.hs
--- a/src/Data/Type/Util.hs
+++ b/src/Data/Type/Util.hs
@@ -3,6 +3,7 @@
 {-# LANGUAGE PolyKinds              #-}
 {-# LANGUAGE RankNTypes             #-}
 {-# LANGUAGE ScopedTypeVariables    #-}
+{-# LANGUAGE TupleSections          #-}
 {-# LANGUAGE TypeFamilyDependencies #-}
 {-# LANGUAGE TypeOperators          #-}
 
@@ -18,15 +19,20 @@
   , listToVecDef
   , fillProd
   , zipVecList
+  , splitProd
+  , p1, p2, s1, s2
   ) where
 
 import           Data.Bifunctor
-import           Data.Type.Conjunction
+import           Data.Type.Conjunction hiding ((:*:))
 import           Data.Type.Length
 import           Data.Type.Nat
 import           Data.Type.Product
 import           Data.Type.Vector
+import           GHC.Generics
+import           Lens.Micro
 import           Type.Class.Witness
+import           Type.Family.List
 import           Type.Family.Nat
 
 -- | @'Replicate' n a@ is a list of @a@s repeated @n@ times.
@@ -156,3 +162,31 @@
       x :* xs -> \case
         []   -> f x Nothing  :* go xs []
         y:ys -> f x (Just y) :* go xs ys
+
+splitProd
+    :: Length as
+    -> Prod f (as ++ bs)
+    -> (Prod f as, Prod f bs)
+splitProd = \case
+    LZ   -> (Ø,)
+    LS l -> \case
+      x :< xs -> first (x :<) $ splitProd l xs
+{-# INLINE splitProd #-}
+
+p1 :: Lens' ((f :*: g) a) (f a)
+p1 f (x :*: y) = (:*: y) <$> f x
+{-# INLINE p1 #-}
+
+p2 :: Lens' ((f :*: g) a) (g a)
+p2 f (x :*: y) = (x :*:) <$> f y
+{-# INLINE p2 #-}
+
+s1 :: Traversal' ((f :+: g) a) (f a)
+s1 f (L1 x) = L1 <$> f x
+s1 _ (R1 y) = pure (R1 y)
+{-# INLINE s1 #-}
+
+s2 :: Traversal' ((f :+: g) a) (g a)
+s2 _ (L1 x) = pure (L1 x)
+s2 f (R1 y) = R1 <$> f y
+{-# INLINE s2 #-}
diff --git a/src/Numeric/Backprop.hs b/src/Numeric/Backprop.hs
--- a/src/Numeric/Backprop.hs
+++ b/src/Numeric/Backprop.hs
@@ -48,6 +48,10 @@
 -- and links to demonstrations and tutorials, or dive striaght in by
 -- reading the docs for 'BVar'.
 --
+-- If you are writing a library, see
+-- <https://github.com/mstksg/backprop/wiki/Equipping-your-Library-with-Backprop>
+-- for a guide for equipping your library with backpropatable operations.
+--
 -- In the original version 0.1, this module required 'Num' instances for
 -- methods instead of 'Backprop' instances.  This interface is still
 -- available in "Numeric.Backprop.Num", which has the same API as this
@@ -69,6 +73,7 @@
   , backprop2, E.evalBP2, gradBP2, backpropWith2
   , backpropN, E.evalBPN, gradBPN, backpropWithN, Every
     -- * Manipulating 'BVar'
+  , E.evalBP0
   , E.constVar, E.auto, E.coerceVar
   , (^^.), (.~~), (^^?), (^^..), (^^?!)
   , viewVar, setVar
@@ -81,6 +86,11 @@
     -- $liftops
   , liftOp
   , liftOp1, liftOp2, liftOp3
+    -- ** Generics#hkd#
+    -- $hkd
+  , splitBV
+  , joinBV
+  , E.BVGroup
     -- * 'Op'
   , Op(..)
     -- ** Creation
@@ -105,6 +115,7 @@
 import           Data.Reflection
 import           Data.Type.Index
 import           Data.Type.Length
+import           GHC.Generics
 import           Lens.Micro
 import           Numeric.Backprop.Class
 import           Numeric.Backprop.Explicit (BVar, W)
@@ -336,11 +347,15 @@
 --
 -- This is the main way to pull out values from 'BVar' of container types.
 --
+-- If you have control of your data type definitions, consider using
+-- 'splitBV', which lets you break out 'BVar's of values into 'BVar's of
+-- their individual fields automatically without requiring lenses.
+--
 -- __WARNING__: Do not use with any lenses that operate "numerically" on
 -- the contents (like 'multiplying').
 --
 (^^.)
-    :: forall a b s. (Reifies s W, Backprop a)
+    :: forall b a s. (Backprop a, Reifies s W)
     => BVar s b
     -> Lens' b a
     -> BVar s a
@@ -351,9 +366,13 @@
 -- | Using a 'Lens'', extract a value /inside/ a 'BVar'.  Meant to evoke
 -- parallels to 'view' from lens.
 --
+-- If you have control of your data type definitions, consider using
+-- 'splitBV', which lets you break out 'BVar's of values into 'BVar's of
+-- their individual fields automatically without requiring lenses.
+--
 -- See documentation for '^^.' for more information.
 viewVar
-    :: forall a b s. (Reifies s W, Backprop a)
+    :: forall a b s. (Backprop a, Reifies s W)
     => Lens' b a
     -> BVar s b
     -> BVar s a
@@ -385,7 +404,7 @@
 -- This is the main way to set values inside 'BVar's of container types.
 --
 (.~~)
-    :: forall a b s. (Reifies s W, Backprop a, Backprop b)
+    :: (Backprop a, Backprop b, Reifies s W)
     => Lens' b a
     -> BVar s a
     -> BVar s b
@@ -399,7 +418,7 @@
 --
 -- See documentation for '.~~' for more information.
 setVar
-    :: forall a b s. (Reifies s W, Backprop a, Backprop b)
+    :: (Backprop a, Backprop b, Reifies s W)
     => Lens' b a
     -> BVar s a
     -> BVar s b
@@ -469,7 +488,7 @@
 --
 -- See documentation for '^^?' for more information.
 previewVar
-    :: forall b a s. (Reifies s W, Backprop a)
+    :: forall b a s. (Backprop a, Reifies s W)
     => Traversal' b a
     -> BVar s b
     -> Maybe (BVar s a)
@@ -526,7 +545,7 @@
 -- unexpected behavior in 'Foldable' instances that don't have a fixed
 -- number of items.
 sequenceVar
-    :: forall t a s. (Backprop a, Reifies s W, Traversable t)
+    :: (Traversable t, Backprop a, Reifies s W)
     => BVar s (t a)
     -> t (BVar s a)
 sequenceVar = E.sequenceVar E.addFunc E.zeroFunc
@@ -541,7 +560,7 @@
 -- etc.; this can cause unexpected behavior in 'Foldable' instances that
 -- don't have a fixed number of items.
 collectVar
-    :: forall t a s. (Backprop a, Backprop (t a), Reifies s W, Foldable t, Functor t)
+    :: (Foldable t, Functor t, Backprop a, Backprop (t a), Reifies s W)
     => t (BVar s a)
     -> BVar s (t a)
 collectVar = E.collectVar E.addFunc E.zeroFunc E.zeroFunc
@@ -557,7 +576,7 @@
 -- information, and "Numeric.Backprop.Op#prod" for a mini-tutorial on using
 -- 'Prod' and 'Tuple'.
 liftOp
-    :: forall as b s. (Every Backprop as, Known Length as, Backprop b, Reifies s W)
+    :: (Every Backprop as, Known Length as, Backprop b, Reifies s W)
     => Op as b
     -> Prod (BVar s) as
     -> BVar s b
@@ -572,7 +591,7 @@
 -- See "Numeric.Backprop#liftops" and documentation for 'liftOp' for more
 -- information.
 liftOp1
-    :: forall a b s. (Backprop a, Backprop b, Reifies s W)
+    :: (Backprop a, Backprop b, Reifies s W)
     => Op '[a] b
     -> BVar s a
     -> BVar s b
@@ -587,7 +606,7 @@
 -- See "Numeric.Backprop#liftops" and documentation for 'liftOp' for more
 -- information.
 liftOp2
-    :: forall a b c s. (Backprop a, Backprop b, Backprop c, Reifies s W)
+    :: (Backprop a, Backprop b, Backprop c, Reifies s W)
     => Op '[a,b] c
     -> BVar s a
     -> BVar s b
@@ -603,7 +622,7 @@
 -- See "Numeric.Backprop#liftops" and documentation for 'liftOp' for more
 -- information.
 liftOp3
-    :: forall a b c d s. (Backprop a, Backprop b, Backprop c, Backprop d, Reifies s W)
+    :: (Backprop a, Backprop b, Backprop c, Backprop d, Reifies s W)
     => Op '[a,b,c] d
     -> BVar s a
     -> BVar s b
@@ -615,6 +634,10 @@
 -- | Convert the value inside a 'BVar' using a given isomorphism.  Useful
 -- for things like constructors.
 --
+-- If you have control of your data type definitions, consider using
+-- 'joinBV', which lets you use your data type constructors themselves to
+-- join together 'BVar's as their fields.
+--
 -- 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.
@@ -632,6 +655,10 @@
 -- | Convert the values inside two 'BVar's using a given isomorphism.
 -- Useful for things like constructors.  See 'isoVar' for caveats.
 --
+-- If you have control of your data type definitions, consider using
+-- 'joinBV', which lets you use your data type constructors themselves to
+-- join together 'BVar's as their fields.
+--
 -- @since 0.1.4.0
 isoVar2
     :: (Backprop a, Backprop b, Backprop c, Reifies s W)
@@ -662,6 +689,10 @@
 -- isomorphism. Useful for things like constructors.  See 'isoVar' for
 -- caveats.
 --
+-- If you have control of your data type definitions, consider using
+-- 'joinBV', which lets you use your data type constructors themselves to
+-- join together 'BVar's as their fields.
+--
 -- @since 0.1.4.0
 isoVarN
     :: (Every Backprop as, Known Length as, Backprop b, Reifies s W)
@@ -684,6 +715,7 @@
 pattern T2 x y <- (\xy -> (xy ^^. _1, xy ^^. _2) -> (x, y))
   where
     T2 = isoVar2 (,) id
+{-# COMPLETE T2 #-}
 
 -- | Useful pattern for constructing and deconstructing 'BVar's
 -- three-tuples.
@@ -698,4 +730,135 @@
 pattern T3 x y z <- (\xyz -> (xyz ^^. _1, xyz ^^. _2, xyz ^^. _3) -> (x, y, z))
   where
     T3 = isoVar3 (,,) id
+{-# COMPLETE T3 #-}
 
+-- $hkd
+--
+-- 'splitBV' and 'joinBV' let you split out a 'BVar' of a data type and
+-- join together a data type of 'BVar's using the "higher-kinded data type"
+-- technique, a la
+-- <http://reasonablypolymorphic.com/blog/higher-kinded-data/>.
+--
+-- It will let you take a data type like
+--
+-- @
+-- data MyType = MT { mtX :: 'Double', mtY :: [Double] }
+--
+-- -- | Automatic instance
+-- instance Backprop MyType
+-- @
+--
+-- And automatically let you turn a @'BVar' s MyType@ into a @'BVar'
+-- s 'Double'@ and @BVar s [Double]@, without munging around with lenses
+-- and 'viewVar'.  It'll also let you take a @BVar s Double@ and a @BVar
+-- s [Double]@ and turn it into a @BVar s MyType@ without messing around
+-- with manually lifting ops or 'isoVar'.
+--
+-- To do this, rewrite 'MyType' to take a 'Functor' argument:
+--
+-- @
+-- -- | Can be re-used for every data type you use this trick with
+-- type family HKD f a where
+--     HKD 'Identity' a = a
+--     HKD f        a =  f a
+--
+-- data MyType' f = MT { mtX :: HKD f Double, mtY :: HKD f [Double] }
+--   deriving Generic
+--
+-- -- | This is the original data type, which can be used the same way as
+-- -- before
+-- type MyType = MyType' 'Identity'
+--
+-- -- | Automatic instance
+-- instance 'Backprop' MyType
+-- @
+--
+-- Now, 'splitBV' can be used, with type:
+--
+-- @
+-- 'splitBV' :: BVar s MyType -> MyType' (BVar s)
+-- @
+--
+-- So you can use it lke:
+--
+-- @
+-- myFunction :: 'BVar' s MyType -> BVar s Double
+-- myFunction ('splitBV' -> MT x y) =  x + 'Prelude.Backprop.sum' y
+-- @
+--
+-- If you use 'splitBV', the contents will be a @BVar s Double@ and a @BVar
+-- s [Double]@.  It lets you "extract" the fields, because your 'MyType''
+-- constructor now holds a @'BVar' s Double@ and a @BVar s [Double]@,
+-- instead of just a normal 'Double' and @[Double]@.
+--
+-- With this trick, 'joinBV' can also be used, with the type:
+--
+-- @
+-- 'joinBV' :: MyType' (BVar s) -> BVar s MyType
+-- @
+--
+-- So you can take a bunch of 'BVar's and turn them into a 'BVar' of
+-- a 'MyType':
+--
+-- @
+-- myOtherFunction :: 'BVar' s Double -> BVar s [Double] -> BVar s MyType
+-- myOtherFunction x y = 'joinBV' $ MT x y
+-- @
+--
+-- This will work with all data types made with a single constructor, whose
+-- fields are all instances of 'Backprop', where the type itself has an
+-- instance of 'Backprop'.
+
+-- | Split out a 'BVar' of "higher-kinded data type", a la
+-- <http://reasonablypolymorphic.com/blog/higher-kinded-data/>
+--
+-- Lets you take 'BVar' of a value into a separate 'BVar' of every field of
+-- that value.
+--
+-- See "Numeric.Backprop#hkd" for a tutorial on usage.
+--
+-- This will work with all data types made with a single constructor, whose
+-- fields are all instances of 'Backprop', where the type itself has an
+-- instance of 'Backprop'.  The type also must derive 'Generic'.
+--
+-- @since 0.2.2.0
+splitBV
+    :: ( Generic (z f)
+       , Generic (z (BVar s))
+       , E.BVGroup s as (Rep (z f)) (Rep (z (BVar s)))
+       , Backprop (Rep (z f) ())
+       , Every Backprop as
+       , Known Length as
+       , Reifies s W
+       )
+    => BVar s (z f)             -- ^ 'BVar' of value
+    -> z (BVar s)               -- ^ 'BVar's of fields
+splitBV = E.splitBV E.addFunc E.addFuncs E.zeroFunc E.zeroFuncs
+{-# INLINE splitBV #-}
+
+-- | Split out a 'BVar' of "higher-kinded data type", a la
+-- <http://reasonablypolymorphic.com/blog/higher-kinded-data/>
+--
+-- It lets you take a 'BVar' of every field of a value, and join them into
+-- a 'BVar' of that value.
+--
+-- See "Numeric.Backprop#hkd" for a tutorial on usage.
+--
+-- This will work with all data types made with a single constructor, whose
+-- fields are all instances of 'Backprop', where the type itself has an
+-- instance of 'Backprop'.
+--
+-- @since 0.2.2.0
+joinBV
+    :: ( Generic (z f)
+       , Generic (z (BVar s))
+       , E.BVGroup s as (Rep (z f)) (Rep (z (BVar s)))
+       , Backprop (z f)
+       , Every Backprop as
+       , Known Length as
+       , Reifies s W
+       )
+    => z (BVar s)           -- ^ 'BVar's of fields
+    -> BVar s (z f)         -- ^ 'BVar' of combined value
+joinBV = E.joinBV E.addFunc E.addFuncs E.zeroFunc E.zeroFuncs
+{-# INLINE joinBV #-}
diff --git a/src/Numeric/Backprop/Class.hs b/src/Numeric/Backprop/Class.hs
--- a/src/Numeric/Backprop/Class.hs
+++ b/src/Numeric/Backprop/Class.hs
@@ -1,4 +1,5 @@
 {-# LANGUAGE BangPatterns               #-}
+{-# LANGUAGE DataKinds                  #-}
 {-# LANGUAGE DefaultSignatures          #-}
 {-# LANGUAGE DeriveDataTypeable         #-}
 {-# LANGUAGE DeriveFoldable             #-}
@@ -7,6 +8,7 @@
 {-# LANGUAGE DeriveTraversable          #-}
 {-# LANGUAGE EmptyCase                  #-}
 {-# LANGUAGE FlexibleContexts           #-}
+{-# LANGUAGE FlexibleInstances          #-}
 {-# LANGUAGE GADTs                      #-}
 {-# LANGUAGE GeneralizedNewtypeDeriving #-}
 {-# LANGUAGE LambdaCase                 #-}
@@ -41,7 +43,7 @@
   -- * Newtype
   , ABP(..), NumBP(..)
   -- * Generics
-  , GZero(..), GAdd(..), GOne(..)
+  , GZero, GAdd, GOne
   ) where
 
 import           Control.Applicative
@@ -49,27 +51,36 @@
 import           Data.Coerce
 import           Data.Complex
 import           Data.Data
-import           Data.Foldable hiding        (toList)
+import           Data.Foldable hiding         (toList)
 import           Data.Functor.Identity
-import           Data.List.NonEmpty          (NonEmpty(..))
+import           Data.List.NonEmpty           (NonEmpty(..))
+import           Data.Monoid
 import           Data.Ratio
-import           Data.Type.Combinator hiding ((:.:), Comp1)
+import           Data.Type.Combinator hiding  ((:.:), Comp1)
+import           Data.Type.Conjunction hiding ((:*:))
 import           Data.Type.Option
-import           Data.Type.Product hiding    (toList)
+import           Data.Type.Product hiding     (toList)
 import           Data.Void
+import           Data.Word
 import           GHC.Exts
 import           GHC.Generics
 import           Numeric.Natural
 import           Type.Family.List
-import qualified Data.IntMap                 as IM
-import qualified Data.Map                    as M
-import qualified Data.Sequence               as Seq
-import qualified Data.Vector                 as V
-import qualified Data.Vector.Generic         as VG
-import qualified Data.Vector.Primitive       as VP
-import qualified Data.Vector.Storable        as VS
-import qualified Data.Vector.Unboxed         as VU
-import qualified Type.Family.Maybe           as M
+import qualified Control.Arrow                as Arr
+import qualified Data.Functor.Compose         as DFC
+import qualified Data.Functor.Product         as DFP
+import qualified Data.IntMap                  as IM
+import qualified Data.Map                     as M
+import qualified Data.Semigroup               as SG
+import qualified Data.Sequence                as Seq
+import qualified Data.Type.Combinator         as TC
+import qualified Data.Type.Conjunction        as TC
+import qualified Data.Vector                  as V
+import qualified Data.Vector.Generic          as VG
+import qualified Data.Vector.Primitive        as VP
+import qualified Data.Vector.Storable         as VS
+import qualified Data.Vector.Unboxed          as VU
+import qualified Type.Family.Maybe            as M
 
 -- | Class of values that can be backpropagated in general.
 --
@@ -534,6 +545,51 @@
     one  = oneNum
     {-# INLINE one #-}
 
+-- | @since 0.2.2.0
+instance Backprop Word8 where
+    zero = zeroNum
+    {-# INLINE zero #-}
+    add  = addNum
+    {-# INLINE add #-}
+    one  = oneNum
+    {-# INLINE one #-}
+
+-- | @since 0.2.2.0
+instance Backprop Word where
+    zero = zeroNum
+    {-# INLINE zero #-}
+    add  = addNum
+    {-# INLINE add #-}
+    one  = oneNum
+    {-# INLINE one #-}
+
+-- | @since 0.2.2.0
+instance Backprop Word16 where
+    zero = zeroNum
+    {-# INLINE zero #-}
+    add  = addNum
+    {-# INLINE add #-}
+    one  = oneNum
+    {-# INLINE one #-}
+
+-- | @since 0.2.2.0
+instance Backprop Word32 where
+    zero = zeroNum
+    {-# INLINE zero #-}
+    add  = addNum
+    {-# INLINE add #-}
+    one  = oneNum
+    {-# INLINE one #-}
+
+-- | @since 0.2.2.0
+instance Backprop Word64 where
+    zero = zeroNum
+    {-# INLINE zero #-}
+    add  = addNum
+    {-# INLINE add #-}
+    one  = oneNum
+    {-# INLINE one #-}
+
 instance Integral a => Backprop (Ratio a) where
     zero = zeroNum
     {-# INLINE zero #-}
@@ -717,15 +773,20 @@
     one (I x) = I (one x)
     {-# INLINE one #-}
 
--- | 'add' is strict, but 'zero' and 'one' are lazy in their arguments.
 instance Backprop (Proxy a) where
     zero _ = Proxy
     {-# INLINE zero #-}
-    add Proxy Proxy = Proxy
+    add _ _ = Proxy
     {-# INLINE add #-}
     one _ = Proxy
     {-# INLINE one #-}
 
+-- | @since 0.2.2.0
+instance Backprop w => Backprop (Const w a) where
+    zero (Const x) = Const (zero x)
+    add (Const x) (Const y) = Const (add x y)
+    one (Const x) = Const (one x)
+
 instance Backprop Void where
     zero = \case {}
     {-# INLINE zero #-}
@@ -786,3 +847,196 @@
       Just_ x  -> Just_ (one x)
     {-# INLINE one #-}
 
+-- | @since 0.2.2.0
+instance (Backprop (f a), Backprop (g a)) => Backprop ((f :&: g) a) where
+    zero (x :&: y) = zero x :&: zero y
+    {-# INLINE zero #-}
+    add (x1 :&: y1) (x2 :&: y2) = add x1 x2 :&: add y1 y2
+    {-# INLINE add #-}
+    one (x :&: y) = one x :&: one y
+    {-# INLINE one #-}
+
+-- | @since 0.2.2.0
+instance (Backprop (f a), Backprop (g b)) => Backprop ((f TC.:*: g) '(a, b)) where
+    zero (x TC.:*: y) = zero x TC.:*: zero y
+    {-# INLINE zero #-}
+    add (x1 TC.:*: y1) (x2 TC.:*: y2) = add x1 x2 TC.:*: add y1 y2
+    {-# INLINE add #-}
+    one (x TC.:*: y) = one x TC.:*: one y
+    {-# INLINE one #-}
+
+-- | @since 0.2.2.0
+instance Backprop (f (g h) a) => Backprop (TC.Comp1 f g h a) where
+    zero (TC.Comp1 x) = TC.Comp1 (zero x)
+    {-# INLINE zero #-}
+    add (TC.Comp1 x) (TC.Comp1 y) = TC.Comp1 (add x y)
+    {-# INLINE add #-}
+    one (TC.Comp1 x) = TC.Comp1 (one x)
+    {-# INLINE one #-}
+
+-- | @since 0.2.2.0
+instance Backprop (f (g a)) => Backprop ((f TC.:.: g) a) where
+    zero (Comp x) = Comp (zero x)
+    {-# INLINE zero #-}
+    add (Comp x) (Comp y) = Comp (add x y)
+    {-# INLINE add #-}
+    one (Comp x) = Comp (one x)
+    {-# INLINE one #-}
+
+-- | @since 0.2.2.0
+instance Backprop w => Backprop (TC.C w a) where
+    zero (TC.C x) = TC.C (zero x)
+    {-# INLINE zero #-}
+    add (TC.C x) (TC.C y) = TC.C (add x y)
+    {-# INLINE add #-}
+    one (TC.C x) = TC.C (one x)
+    {-# INLINE one #-}
+
+-- | @since 0.2.2.0
+instance Backprop (p a b) => Backprop (Flip p b a) where
+    zero (Flip x) = Flip (zero x)
+    {-# INLINE zero #-}
+    add (Flip x) (Flip y) = Flip (add x y)
+    {-# INLINE add #-}
+    one (Flip x) = Flip (one x)
+    {-# INLINE one #-}
+
+-- | @since 0.2.2.0
+instance Backprop (p '(a, b)) => Backprop (Cur p a b) where
+    zero (Cur x) = Cur (zero x)
+    {-# INLINE zero #-}
+    add (Cur x) (Cur y) = Cur (add x y)
+    {-# INLINE add #-}
+    one (Cur x) = Cur (one x)
+    {-# INLINE one #-}
+
+-- | @since 0.2.2.0
+instance Backprop (p a b) => Backprop (Uncur p '(a, b)) where
+    zero (Uncur x) = Uncur (zero x)
+    {-# INLINE zero #-}
+    add (Uncur x) (Uncur y) = Uncur (add x y)
+    {-# INLINE add #-}
+    one (Uncur x) = Uncur (one x)
+    {-# INLINE one #-}
+
+-- | @since 0.2.2.0
+instance Backprop (p '(a, b, c)) => Backprop (Cur3 p a b c) where
+    zero (Cur3 x) = Cur3 (zero x)
+    {-# INLINE zero #-}
+    add (Cur3 x) (Cur3 y) = Cur3 (add x y)
+    {-# INLINE add #-}
+    one (Cur3 x) = Cur3 (one x)
+    {-# INLINE one #-}
+
+-- | @since 0.2.2.0
+instance Backprop (p a b c) => Backprop (Uncur3 p '(a, b, c)) where
+    zero (Uncur3 x) = Uncur3 (zero x)
+    {-# INLINE zero #-}
+    add (Uncur3 x) (Uncur3 y) = Uncur3 (add x y)
+    {-# INLINE add #-}
+    one (Uncur3 x) = Uncur3 (one x)
+    {-# INLINE one #-}
+
+-- | @since 0.2.2.0
+instance Backprop (f a a) => Backprop (Join f a) where
+    zero (Join x) = Join (zero x)
+    {-# INLINE zero #-}
+    add (Join x) (Join y) = Join (add x y)
+    {-# INLINE add #-}
+    one (Join x) = Join (one x)
+    {-# INLINE one #-}
+
+-- | @since 0.2.2.0
+instance Backprop (t (Flip f b) a) => Backprop (Conj t f a b) where
+    zero (Conj x) = Conj (zero x)
+    {-# INLINE zero #-}
+    add (Conj x) (Conj y) = Conj (add x y)
+    {-# INLINE add #-}
+    one (Conj x) = Conj (one x)
+    {-# INLINE one #-}
+
+-- | @since 0.2.2.0
+instance Backprop (c (f a)) => Backprop (LL c a f) where
+    zero (LL x) = LL (zero x)
+    {-# INLINE zero #-}
+    add (LL x) (LL y) = LL (add x y)
+    {-# INLINE add #-}
+    one (LL x) = LL (one x)
+    {-# INLINE one #-}
+
+-- | @since 0.2.2.0
+instance Backprop (c (f a)) => Backprop (RR c f a) where
+    zero (RR x) = RR (zero x)
+    {-# INLINE zero #-}
+    add (RR x) (RR y) = RR (add x y)
+    {-# INLINE add #-}
+    one (RR x) = RR (one x)
+    {-# INLINE one #-}
+
+-- | @since 0.2.2.0
+instance Backprop a => Backprop (K1 i a p)
+
+-- | @since 0.2.2.0
+instance Backprop (f p) => Backprop (M1 i c f p)
+
+-- | @since 0.2.2.0
+instance (Backprop (f p), Backprop (g p)) => Backprop ((f :*: g) p)
+
+-- | @since 0.2.2.0
+instance Backprop (V1 p)
+
+-- | @since 0.2.2.0
+instance Backprop (U1 p)
+
+-- | @since 0.2.2.0
+instance Backprop a => Backprop (Sum a)
+
+-- | @since 0.2.2.0
+instance Backprop a => Backprop (Product a)
+
+-- | @since 0.2.2.0
+instance Backprop a => Backprop (SG.Option a)
+
+-- | @since 0.2.2.0
+instance Backprop a => Backprop (SG.First a)
+
+-- | @since 0.2.2.0
+instance Backprop a => Backprop (SG.Last a)
+
+-- | @since 0.2.2.0
+instance Backprop a => Backprop (First a)
+
+-- | @since 0.2.2.0
+instance Backprop a => Backprop (Data.Monoid.Last a)
+
+-- | @since 0.2.2.0
+instance Backprop a => Backprop (Dual a)
+
+-- | @since 0.2.2.0
+instance (Backprop a, Backprop b) => Backprop (SG.Arg a b)
+
+-- | @since 0.2.2.0
+instance (Backprop (f a), Backprop (g a)) => Backprop (DFP.Product f g a)
+
+-- | @since 0.2.2.0
+instance Backprop (f (g a)) => Backprop (DFC.Compose f g a)
+
+-- | 'add' adds together results; 'zero' and 'one' act on results.
+--
+-- @since 0.2.2.0
+instance Backprop a => Backprop (r -> a) where
+    zero = fmap zero
+    {-# INLINE zero #-}
+    add  = liftA2 add
+    {-# INLINE add #-}
+    one  = fmap one
+    {-# INLINE one #-}
+
+-- | @since 0.2.2.0
+instance (Backprop a, Applicative m) => Backprop (Arr.Kleisli m r a) where
+    zero (Arr.Kleisli f) = Arr.Kleisli ((fmap . fmap) zero f)
+    {-# INLINE zero #-}
+    add (Arr.Kleisli f) (Arr.Kleisli g) = Arr.Kleisli $ \x ->
+        add <$> f x <*> g x
+    one (Arr.Kleisli f) = Arr.Kleisli ((fmap . fmap) one f)
+    {-# INLINE one #-}
diff --git a/src/Numeric/Backprop/Explicit.hs b/src/Numeric/Backprop/Explicit.hs
--- a/src/Numeric/Backprop/Explicit.hs
+++ b/src/Numeric/Backprop/Explicit.hs
@@ -1,8 +1,18 @@
-{-# LANGUAGE FlexibleContexts #-}
-{-# LANGUAGE GADTs            #-}
-{-# LANGUAGE PatternSynonyms  #-}
-{-# LANGUAGE RankNTypes       #-}
-{-# LANGUAGE TypeApplications #-}
+{-# LANGUAGE DataKinds              #-}
+{-# LANGUAGE EmptyCase              #-}
+{-# LANGUAGE FlexibleContexts       #-}
+{-# LANGUAGE FlexibleInstances      #-}
+{-# LANGUAGE FunctionalDependencies #-}
+{-# LANGUAGE GADTs                  #-}
+{-# LANGUAGE LambdaCase             #-}
+{-# LANGUAGE MultiParamTypeClasses  #-}
+{-# LANGUAGE PatternSynonyms        #-}
+{-# LANGUAGE RankNTypes             #-}
+{-# LANGUAGE ScopedTypeVariables    #-}
+{-# LANGUAGE TypeApplications       #-}
+{-# LANGUAGE TypeOperators          #-}
+{-# LANGUAGE UndecidableInstances   #-}
+{-# OPTIONS_HADDOCK not-home        #-}
 
 -- |
 -- Module      : Numeric.Backprop.Explicit
@@ -37,6 +47,7 @@
     -- * Running
   , backprop, evalBP, gradBP, backpropWith
     -- ** Multiple inputs
+  , evalBP0
   , backprop2, evalBP2, gradBP2, backpropWith2
   , backpropN, evalBPN, gradBPN, backpropWithN, Every
     -- * Manipulating 'BVar'
@@ -49,6 +60,10 @@
     -- ** With 'Op's
   , liftOp
   , liftOp1, liftOp2, liftOp3
+    -- ** Generics
+  , splitBV
+  , joinBV
+  , BVGroup
     -- * 'Op'
   , Op(..)
     -- ** Creation
@@ -74,12 +89,17 @@
 import           Data.Type.Index
 import           Data.Type.Length
 import           Data.Type.Product
+import           Data.Type.Util
+import           GHC.Generics              as G
+import           Lens.Micro
 import           Numeric.Backprop.Class
 import           Numeric.Backprop.Internal
 import           Numeric.Backprop.Op
 import           Type.Class.Higher
 import           Type.Class.Known
 import           Type.Class.Witness
+import           Type.Family.List
+import           Unsafe.Coerce
 
 -- | 'ZeroFunc's for every item in a type level list based on their
 -- 'Num' instances
@@ -116,27 +136,6 @@
 ofFunctor = OF oneFunctor
 {-# INLINE ofFunctor #-}
 
--- | The canonical 'ZeroFunc' for instances of 'Backprop'.
---
--- @since 0.2.0.0
-zeroFunc :: Backprop a => ZeroFunc a
-zeroFunc = ZF zero
-{-# INLINE zeroFunc #-}
-
--- | The canonical 'AddFunc' for instances of 'Backprop'.
---
--- @since 0.2.0.0
-addFunc :: Backprop a => AddFunc a
-addFunc = AF add
-{-# INLINE addFunc #-}
-
--- | The canonical 'OneFunc' for instances of 'Backprop'.
---
--- @since 0.2.0.0
-oneFunc :: Backprop a => OneFunc a
-oneFunc = OF one
-{-# INLINE oneFunc #-}
-
 -- | Generate an 'ZeroFunc' for every type in a type-level list, if every
 -- type has an instance of 'Backprop'.
 --
@@ -197,6 +196,12 @@
 backpropWith zfa f x g = backprop zfa (OF g) f x
 {-# INLINE backpropWith #-}
 
+-- | 'evalBP' but with no arguments.  Useful when everything is just given
+-- through 'constVar'.
+evalBP0 :: (forall s. Reifies s W => BVar s a) -> a
+evalBP0 x = evalBPN (const x) Ø
+{-# INLINE evalBP0 #-}
+
 -- | Turn a function @'BVar' s a -> 'BVar' s b@ into the function @a -> b@
 -- that it represents.
 --
@@ -332,3 +337,144 @@
     -> BVar s b
 isoVarN afs z f g = liftOp afs z (opIsoN f g)
 {-# INLINE isoVarN #-}
+
+-- | Helper class for generically "splitting" and "joining" 'BVar's into
+-- constructors.  See 'Numeric.Backprop.splitBV' and
+-- 'Numeric.Backprop.joinBV'.
+--
+-- See "Numeric.Backprop#hkd" for a tutorial on how to use this.
+--
+-- Instances should be available for types made with one constructor whose
+-- fields are all instances of 'Backprop', with a 'Generic' instance.
+--
+-- @since 0.2.2.0
+class BVGroup s as i o | o -> i, i -> as where
+    -- | Helper method for generically "splitting" 'BVar's out of
+    -- constructors inside a 'BVar'.  See 'splitBV'.
+    gsplitBV :: Prod AddFunc as -> Prod ZeroFunc as -> BVar s (i ()) -> o ()
+    -- | Helper method for generically "joining" 'BVar's inside
+    -- a constructor into a 'BVar'.  See 'joinBV'.
+    gjoinBV  :: Prod AddFunc as -> Prod ZeroFunc as -> o () -> BVar s (i ())
+
+instance BVGroup s '[] (K1 i a) (K1 i (BVar s a)) where
+    gsplitBV _ _ = K1 . coerceVar
+    {-# INLINE gsplitBV #-}
+    gjoinBV  _ _ = coerceVar . unK1
+    {-# INLINE gjoinBV #-}
+
+instance BVGroup s as i o
+        => BVGroup s as (M1 p c i) (M1 p c o) where
+    gsplitBV afs zfs = M1 . gsplitBV afs zfs . coerceVar @_ @(i ())
+    {-# INLINE gsplitBV #-}
+    gjoinBV afs zfs = coerceVar @(i ()) . gjoinBV afs zfs . unM1
+    {-# INLINE gjoinBV #-}
+
+instance BVGroup s '[] V1 V1 where
+    gsplitBV _ _ = unsafeCoerce
+    {-# INLINE gsplitBV #-}
+    gjoinBV _ _ = \case
+    {-# INLINE gjoinBV #-}
+
+instance BVGroup s '[] U1 U1 where
+    gsplitBV _ _ _ = U1
+    {-# INLINE gsplitBV #-}
+    gjoinBV _ _ _ = constVar U1
+    {-# INLINE gjoinBV #-}
+
+instance ( Reifies s W
+         , BVGroup s as i1 o1
+         , BVGroup s bs i2 o2
+         , cs ~ (as ++ bs)
+         , Known Length as
+         ) => BVGroup s (i1 () ': i2 () ': cs) (i1 :*: i2) (o1 :*: o2) where
+    gsplitBV (afa :< afb :< afs) (zfa :< zfb :< zfs) xy = x :*: y
+      where
+        (afas, afbs) = splitProd known afs
+        (zfas, zfbs) = splitProd known zfs
+        x = gsplitBV afas zfas . viewVar afa zfa p1 $ xy
+        y = gsplitBV afbs zfbs . viewVar afb zfb p2 $ xy
+    {-# INLINE gsplitBV #-}
+    gjoinBV (afa :< afb :< afs) (zfa :< zfb :< zfs) (x :*: y)
+        = isoVar2 afa afb zfab (:*:) unP
+            (gjoinBV afas zfas x)
+            (gjoinBV afbs zfbs y)
+      where
+        zfab = ZF $ \(xx :*: yy) -> runZF zfa xx :*: runZF zfb yy
+        (afas, afbs) = splitProd known afs
+        (zfas, zfbs) = splitProd known zfs
+        unP (xx :*: yy) = (xx, yy)
+    {-# INLINE gjoinBV #-}
+
+-- | This instance is possible but it is not clear when it would be useful
+instance ( Reifies s W
+         , BVGroup s as i1 o1
+         , BVGroup s bs i2 o2
+         , cs ~ (as ++ bs)
+         , Known Length as
+         ) => BVGroup s (i1 () ': i2 () ': cs) (i1 :+: i2) (o1 :+: o2) where
+    gsplitBV (afa :< afb :< afs) (zfa :< zfb :< zfs) xy =
+        case previewVar afa zfa s1 xy of
+          Just x -> L1 $ gsplitBV afas zfas x
+          Nothing -> case previewVar afb zfb s2 xy of
+            Just y -> R1 $ gsplitBV afbs zfbs y
+            Nothing -> error "Numeric.Backprop.gsplitBV: Internal error occurred"
+      where
+        (afas, afbs) = splitProd known afs
+        (zfas, zfbs) = splitProd known zfs
+    {-# INLINE gsplitBV #-}
+    gjoinBV (afa :< afb :< afs) (zfa :< zfb :< zfs) = \case
+        L1 x -> liftOp1 afa zf (op1 (\xx -> (L1 xx, \case L1 d -> d; R1 _ -> runZF zfa xx)))
+                    (gjoinBV afas zfas x)
+        R1 y -> liftOp1 afb zf (op1 (\yy -> (R1 yy, \case L1 _ -> runZF zfb yy; R1 d -> d)))
+                    (gjoinBV afbs zfbs y)
+      where
+        (afas, afbs) = splitProd known afs
+        (zfas, zfbs) = splitProd known zfs
+        zf = ZF $ \case
+            L1 xx -> L1 $ runZF zfa xx
+            R1 yy -> R1 $ runZF zfb yy
+    {-# INLINE gjoinBV #-}
+
+-- | 'Numeric.Backprop.splitBV' with explicit 'add' and 'zero'.
+--
+-- @since 0.2.2.0
+splitBV
+    :: forall z f s as.
+       ( Generic (z f)
+       , Generic (z (BVar s))
+       , BVGroup s as (Rep (z f)) (Rep (z (BVar s)))
+       , Reifies s W
+       )
+    => AddFunc (Rep (z f) ())
+    -> Prod AddFunc as
+    -> ZeroFunc (Rep (z f) ())
+    -> Prod ZeroFunc as
+    -> BVar s (z f)             -- ^ 'BVar' of value
+    -> z (BVar s)               -- ^ 'BVar's of fields
+splitBV af afs zf zfs =
+        G.to
+      . gsplitBV afs zfs
+      . viewVar af zf (lens (from @(z f) @()) (const G.to))
+{-# INLINE splitBV #-}
+
+-- | 'Numeric.Backprop.joinBV' with explicit 'add' and 'zero'.
+--
+-- @since 0.2.2.0
+joinBV
+    :: forall z f s as.
+       ( Generic (z f)
+       , Generic (z (BVar s))
+       , BVGroup s as (Rep (z f)) (Rep (z (BVar s)))
+       , Reifies s W
+       )
+    => AddFunc (z f)
+    -> Prod AddFunc as
+    -> ZeroFunc (z f)
+    -> Prod ZeroFunc as
+    -> z (BVar s)           -- ^ 'BVar's of fields
+    -> BVar s (z f)         -- ^ 'BVar' of combined value
+joinBV af afs zf zfs =
+        viewVar af zf (lens G.to (const from))
+      . gjoinBV afs zfs
+      . from @(z (BVar s)) @()
+{-# INLINE joinBV #-}
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
@@ -1,6 +1,7 @@
 {-# LANGUAGE BangPatterns        #-}
 {-# LANGUAGE DeriveDataTypeable  #-}
 {-# LANGUAGE DeriveGeneric       #-}
+{-# LANGUAGE EmptyCase           #-}
 {-# LANGUAGE FlexibleContexts    #-}
 {-# LANGUAGE GADTs               #-}
 {-# LANGUAGE RankNTypes          #-}
@@ -12,6 +13,7 @@
 {-# LANGUAGE TypeInType          #-}
 {-# LANGUAGE TypeOperators       #-}
 {-# LANGUAGE ViewPatterns        #-}
+{-# OPTIONS_HADDOCK not-home     #-}
 
 -- |
 -- Module      : Numeric.Backprop.Internal
@@ -34,9 +36,9 @@
   , viewVar, setVar, sequenceVar, collectVar, previewVar, toListOfVar
   , coerceVar
   -- * Func wrappers
-  , ZeroFunc(..), zfNum
-  , AddFunc(..), afNum
-  , OneFunc(..), ofNum
+  , ZeroFunc(..), zfNum, zeroFunc
+  , AddFunc(..), afNum, addFunc
+  , OneFunc(..), ofNum, oneFunc
   -- * Debug
   , debugSTN
   , debugIR
@@ -55,23 +57,24 @@
 import           Data.IORef
 import           Data.Kind
 import           Data.Maybe
-import           Data.Monoid hiding        (Any(..))
+import           Data.Monoid hiding           (Any(..))
 import           Data.Proxy
 import           Data.Reflection
-import           Data.Type.Conjunction
-import           Data.Type.Product hiding  (toList)
+import           Data.Type.Conjunction hiding ((:*:))
+import           Data.Type.Product hiding     (toList)
 import           Data.Type.Util
-import           Data.Type.Vector hiding   (itraverse)
+import           Data.Type.Vector hiding      (itraverse)
 import           Data.Typeable
-import           GHC.Exts                  (Any)
-import           GHC.Generics
+import           GHC.Exts                     (Any)
+import           GHC.Generics                 as G
 import           Lens.Micro
+import           Numeric.Backprop.Class
 import           Numeric.Backprop.Op
 import           System.IO.Unsafe
 import           Type.Class.Higher
 import           Unsafe.Coerce
-import qualified Data.Vector               as V
-import qualified Data.Vector.Mutable       as MV
+import qualified Data.Vector                  as V
+import qualified Data.Vector.Mutable          as MV
 
 -- | "Zero out" all components of a value.  For scalar values, this should
 -- just be @'const' 0@.  For vectors and matrices, this should set all
@@ -144,23 +147,32 @@
 --
 -- If @a@ contains items, the items can be accessed and extracted using
 -- lenses. A @'Lens'' b a@ can be used to access an @a@ inside a @b@, using
--- '^^.' ('viewVar'):
+-- '^^.' ('Numeric.Backprop.viewVar'):
 --
 -- @
 -- ('^.')  ::        a -> 'Lens'' a b ->        b
 -- ('^^.') :: 'BVar' s a -> 'Lens'' a b -> 'BVar' s b
 -- @
 --
--- There is also '^^?' ('previewVar'), to use a 'Prism'' or 'Traversal'' to
--- extract a target that may or may not be present (which can implement
--- pattern matching), '^^..' ('toListOfVar') to use a 'Traversal'' to
--- extract /all/ targets inside a 'BVar', and '.~~' ('setVar') to set and
--- update values inside a 'BVar'.
+-- There is also '^^?' ('Numeric.Backprop.previewVar'), to use a 'Prism''
+-- or 'Traversal'' to extract a target that may or may not be present
+-- (which can implement pattern matching), '^^..'
+-- ('Numeric.Backprop.toListOfVar') to use a 'Traversal'' to extract /all/
+-- targets inside a 'BVar', and '.~~' ('setVar') to set and update values
+-- inside a 'BVar'.
 --
+-- If you have control over your data type definitions, you can also use
+-- 'Numeric.Backprop.splitBV' and 'Numeric.Backprop.joinBV' to manipulate
+-- data types by easily extracting fields out of a 'BVar' of data types and
+-- creating 'BVar's of data types out of 'BVar's of their fields.  See
+-- "Numeric.Backprop#hkd" for a tutorial on this use pattern.
+--
 -- For more complex operations, libraries can provide functions on 'BVar's
--- using 'liftOp' and related functions.  This is how you can create
--- primitive functions that users can use to manipulate your library's
--- values.
+-- using 'Numeric.Backprop.liftOp' and related functions.  This is how you
+-- can create primitive functions that users can use to manipulate your
+-- library's values.  See
+-- <https://github.com/mstksg/backprop/wiki/Equipping-your-Library-with-Backprop>
+-- for a detailed guide.
 --
 -- For example, the /hmatrix/ library has a matrix-vector multiplication
 -- function, @#> :: L m n -> R n -> L m@.
@@ -169,8 +181,8 @@
 -- (R n) -> BVar (R m)@, which the user can then use to manipulate their
 -- 'BVar's of @L m n@s and @R n@s, etc.
 --
--- See "Numeric.Backprop#liftops" and documentation for 'liftOp' for more
--- information.
+-- See "Numeric.Backprop#liftops" and documentation for
+-- 'Numeric.Backprop.liftOp' for more information.
 --
 data BVar s a = BV { _bvRef :: !(BRef s)
                    , _bvVal :: !a
@@ -618,7 +630,7 @@
                            $ zipWithPM_ go zfs xs
         gradRunner (runOF ofb y) r tp
         delts <- toList <$> V.freeze (_rInputs r)
-        return . fromMaybe (error "backpropN") $
+        return . fromMaybe (internalError "backpropN") $
           fillProd (\_ d -> I (unsafeCoerce d)) xs delts
       where
         go :: forall a. ZeroFunc a -> I a -> ((Sum Int, Endo [Any]),())
@@ -750,7 +762,7 @@
 {-# INLINE itraverse #-}
 
 ixi :: Int -> Lens' [a] a
-ixi _ _ []     = error "ixi"
+ixi _ _ []     = internalError "ixi"
 ixi 0 f (x:xs) = (:xs) <$> f x
 ixi n f (x:xs) = (x:)  <$> ixi (n - 1) f xs
 {-# INLINE ixi #-}
@@ -762,6 +774,43 @@
     stuff    = evalState (traverseOf t (state . const go) xs)
       where
         go :: [a] -> (a,  [a])
-        go []     = error "Numeric.Backprop.Internal: unexpected shape involved in gradient computation"
+        go []     = internalError "ixt"
         go (y:ys) = (y, ys)
 {-# INLINE ixt #-}
+
+-- | @since 0.2.2.0
+instance (Backprop a, Reifies s W) => Backprop (BVar s a) where
+    zero = liftOp1 addFunc zeroFunc . op1 $ \x -> (zero x, zero)
+    {-# INLINE zero #-}
+    add  = liftOp2 addFunc addFunc zeroFunc . op2 $ \x y ->
+        ( add x y
+        , \d -> (d, d)
+        )
+    {-# INLINE add #-}
+    one  = liftOp1 addFunc zeroFunc . op1 $ \x -> (one  x, zero)
+    {-# INLINE one #-}
+
+-- | The canonical 'ZeroFunc' for instances of 'Backprop'.
+--
+-- @since 0.2.0.0
+zeroFunc :: Backprop a => ZeroFunc a
+zeroFunc = ZF zero
+{-# INLINE zeroFunc #-}
+
+-- | The canonical 'AddFunc' for instances of 'Backprop'.
+--
+-- @since 0.2.0.0
+addFunc :: Backprop a => AddFunc a
+addFunc = AF add
+{-# INLINE addFunc #-}
+
+-- | The canonical 'OneFunc' for instances of 'Backprop'.
+--
+-- @since 0.2.0.0
+oneFunc :: Backprop a => OneFunc a
+oneFunc = OF one
+{-# INLINE oneFunc #-}
+
+internalError :: String -> a
+internalError m = errorWithoutStackTrace $
+    "Numeric.Backprop.Internal." ++ m ++ ": unexpected shape involved in gradient computation"
diff --git a/src/Numeric/Backprop/Num.hs b/src/Numeric/Backprop/Num.hs
--- a/src/Numeric/Backprop/Num.hs
+++ b/src/Numeric/Backprop/Num.hs
@@ -3,6 +3,7 @@
 {-# LANGUAGE GADTs            #-}
 {-# LANGUAGE PatternSynonyms  #-}
 {-# LANGUAGE RankNTypes       #-}
+{-# OPTIONS_HADDOCK not-home  #-}
 
 -- |
 -- Module      : Numeric.Backprop.Num
@@ -53,6 +54,7 @@
     -- * Running
   , backprop, E.evalBP, gradBP, backpropWith
     -- ** Multiple inputs
+  , E.evalBP0
   , backprop2, E.evalBP2, gradBP2, backpropWith2
   , backpropN, E.evalBPN, gradBPN, backpropWithN, Every
     -- * Manipulating 'BVar'
@@ -63,8 +65,7 @@
   , previewVar, toListOfVar
     -- ** With Isomorphisms
   , isoVar, isoVar2, isoVar3, isoVarN
-    -- ** With 'Op's#liftops#
-    -- $liftops
+    -- ** With 'Op's
   , liftOp
   , liftOp1, liftOp2, liftOp3
     -- * 'Op'
@@ -213,7 +214,7 @@
 -- | 'Numeric.Backprop.^^.', but with 'Num' constraints instead of
 -- 'Backprop' constraints.
 (^^.)
-    :: forall a b s. (Reifies s W, Num a)
+    :: forall b a s. (Num a, Reifies s W)
     => BVar s b
     -> Lens' b a
     -> BVar s a
@@ -224,7 +225,7 @@
 -- | 'Numeric.Backprop.viewVar', but with 'Num' constraints instead of
 -- 'Backprop' constraints.
 viewVar
-    :: forall a b s. (Reifies s W, Num a)
+    :: forall b a s. (Num a, Reifies s W)
     => Lens' b a
     -> BVar s b
     -> BVar s a
@@ -235,7 +236,7 @@
 -- | 'Numeric.Backprop..~~', but with 'Num' constraints instead of
 -- 'Backprop' constraints.
 (.~~)
-    :: forall a b s. (Reifies s W, Num a, Num b)
+    :: (Num a, Num b, Reifies s W)
     => Lens' b a
     -> BVar s a
     -> BVar s b
@@ -247,7 +248,7 @@
 -- | 'Numeric.Backprop.setVar', but with 'Num' constraints instead of
 -- 'Backprop' constraints.
 setVar
-    :: forall a b s. (Reifies s W, Num a, Num b)
+    :: forall a b s. (Num a, Num b, Reifies s W)
     => Lens' b a
     -> BVar s a
     -> BVar s b
@@ -302,7 +303,7 @@
 --
 -- See documentation for '^^?' for more information and important notes.
 previewVar
-    :: forall b a s. (Reifies s W, Num a)
+    :: forall b a s. (Num a, Reifies s W)
     => Traversal' b a
     -> BVar s b
     -> Maybe (BVar s a)
@@ -332,7 +333,7 @@
 -- | 'Numeric.Backprop.sequenceVar', but with 'Num' constraints instead of
 -- 'Backprop' constraints.
 sequenceVar
-    :: forall t a s. (Num a, Reifies s W, Traversable t)
+    :: (Traversable t, Num a, Reifies s W)
     => BVar s (t a)
     -> t (BVar s a)
 sequenceVar = E.sequenceVar E.afNum E.zfNum
@@ -345,7 +346,7 @@
 -- <https://hackage.haskell.org/package/vector-sized vector-sized> instead:
 -- it's a fixed-length vector type with a very appropriate 'Num' instance!
 collectVar
-    :: forall t a s. (Num a, Num (t a), Reifies s W, Foldable t, Functor t)
+    :: (Foldable t, Functor t, Num a, Num (t a), Reifies s W)
     => t (BVar s a)
     -> BVar s (t a)
 collectVar = E.collectVar E.afNum E.zfNum E.zfNum
@@ -354,7 +355,7 @@
 -- | 'Numeric.Backprop.liftOp', but with 'Num' constraints instead of
 -- 'Backprop' constraints.
 liftOp
-    :: forall as b s. (Every Num as, Known Length as, Num b, Reifies s W)
+    :: (Every Num as, Known Length as, Num b, Reifies s W)
     => Op as b
     -> Prod (BVar s) as
     -> BVar s b
@@ -364,7 +365,7 @@
 -- | 'Numeric.Backprop.liftOp1', but with 'Num' constraints instead of
 -- 'Backprop' constraints.
 liftOp1
-    :: forall a b s. (Num a, Num b, Reifies s W)
+    :: (Num a, Num b, Reifies s W)
     => Op '[a] b
     -> BVar s a
     -> BVar s b
@@ -374,7 +375,7 @@
 -- | 'Numeric.Backprop.liftOp2', but with 'Num' constraints instead of
 -- 'Backprop' constraints.
 liftOp2
-    :: forall a b c s. (Num a, Num b, Num c, Reifies s W)
+    :: (Num a, Num b, Num c, Reifies s W)
     => Op '[a,b] c
     -> BVar s a
     -> BVar s b
@@ -385,7 +386,7 @@
 -- | 'Numeric.Backprop.liftOp3', but with 'Num' constraints instead of
 -- 'Backprop' constraints.
 liftOp3
-    :: forall a b c d s. (Num a, Num b, Num c, Num d, Reifies s W)
+    :: (Num a, Num b, Num c, Num d, Reifies s W)
     => Op '[a,b,c] d
     -> BVar s a
     -> BVar s b
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
@@ -35,6 +35,11 @@
 -- To use these 'Op's with the backprop library, they can be made to work
 -- with 'BVar's using 'liftOp', 'liftOp1', 'liftOp2', and 'liftOp3'.
 --
+-- If you are writing a library, see
+-- <https://github.com/mstksg/backprop/wiki/Equipping-your-Library-with-Backprop>
+-- for a guide for equipping your library with backpropatable operations
+-- using 'Op's.
+--
 
 module Numeric.Backprop.Op (
   -- * Implementation
diff --git a/src/Prelude/Backprop.hs b/src/Prelude/Backprop.hs
--- a/src/Prelude/Backprop.hs
+++ b/src/Prelude/Backprop.hs
@@ -1,6 +1,4 @@
 {-# LANGUAGE FlexibleContexts    #-}
-{-# LANGUAGE RankNTypes          #-}
-{-# LANGUAGE ScopedTypeVariables #-}
 
 -- |
 -- Module      : Prelude.Backprop
@@ -32,6 +30,9 @@
   , minimum
   , maximum
   , traverse
+  , toList
+  , mapAccumL
+  , mapAccumR
   -- * Functor and Applicative
   , fmap
   , (<$>)
@@ -41,100 +42,77 @@
   -- * Misc
   , fromIntegral
   , realToFrac
-  , coerce
+  , E.coerce
   ) where
 
 import           Numeric.Backprop
-import           Prelude             (Num(..), Fractional(..), Eq(..), Ord(..), Functor, Foldable, Traversable, Applicative, (.), ($))
-import qualified Control.Applicative as P
-import qualified Data.Coerce         as C
-import qualified Data.Foldable       as P
-import qualified Prelude             as P
+import           Prelude                   (Num(..), Fractional(..), Ord(..), Functor, Foldable, Traversable, Applicative)
+import qualified Numeric.Backprop.Explicit as E
+import qualified Prelude                   as P
+import qualified Prelude.Backprop.Explicit as E
 
--- | Lifted 'P.sum'
-sum :: forall t a s. (Foldable t, Functor t, Backprop (t a), Backprop a, Num a, Reifies s W)
+-- | Lifted 'P.sum'.  More efficient than going through 'toList'.
+sum :: (Foldable t, Functor t, Backprop (t a), Backprop a, Num a, Reifies s W)
     => BVar s (t a)
     -> BVar s a
-sum = liftOp1 . op1 $ \xs ->
-    ( P.sum xs
-    , (P.<$ xs)
-    )
+sum = E.sum E.addFunc E.zeroFunc
 {-# INLINE sum #-}
 
 -- | Lifted 'P.pure'.
 pure
-    :: forall t a s. (Foldable t, Applicative t, Backprop (t a), Backprop a, Reifies s W)
+    :: (Foldable t, Applicative t, Backprop (t a), Backprop a, Reifies s W)
     => BVar s a
     -> BVar s (t a)
-pure = liftOp1 . op1 $ \x ->
-    ( P.pure x
-    , P.foldl' add (zero x)
-    -- , P.foldl' add zero
-    )
+pure = E.pure E.addFunc E.zeroFunc E.zeroFunc
 {-# INLINE pure #-}
 
--- | Lifted 'P.product'
+-- | Lifted 'P.product'.  More efficient than going through 'toList'.
 product
-    :: forall t a s. (Foldable t, Functor t, Backprop (t a), Backprop a, Fractional a, Reifies s W)
+    :: (Foldable t, Functor t, Backprop (t a), Backprop a, Fractional a, Reifies s W)
     => BVar s (t a)
     -> BVar s a
-product = liftOp1 . op1 $ \xs ->
-    let p = P.product xs
-    in ( p
-       , \d -> (\x -> p * d / x) P.<$> xs
-       )
+product = E.product E.addFunc E.zeroFunc
 {-# INLINE product #-}
 
--- | Lifted 'P.length'.
+-- | Lifted 'P.length'.  More efficient than going through 'toList'.
 length
-    :: forall t a b s. (Foldable t, Backprop (t a), Backprop b, Num b, Reifies s W)
+    :: (Foldable t, Backprop (t a), Backprop b, Num b, Reifies s W)
     => BVar s (t a)
     -> BVar s b
-length = liftOp1 . op1 $ \xs ->
-    ( P.fromIntegral (P.length xs)
-    , P.const (zero xs)
-    )
+length = E.length E.addFunc E.zeroFunc E.zeroFunc
 {-# INLINE length #-}
 
 -- | Lifted 'P.minimum'.  Undefined for situations where 'P.minimum' would
--- be undefined.
+-- be undefined.  More efficient than going through 'toList'.
 minimum
-    :: forall t a s. (Foldable t, Functor t, Backprop a, Ord a, Backprop (t a), Reifies s W)
+    :: (Foldable t, Functor t, Backprop a, Ord a, Backprop (t a), Reifies s W)
     => BVar s (t a)
     -> BVar s a
-minimum = liftOp1 . op1 $ \xs ->
-    let m = P.minimum xs
-    in  ( m
-        , \d -> (\x -> if x == m then d else zero x) P.<$> xs
-        )
+minimum = E.minimum E.addFunc E.zeroFunc
 {-# INLINE minimum #-}
 
 -- | Lifted 'P.maximum'.  Undefined for situations where 'P.maximum' would
--- be undefined.
+-- be undefined.  More efficient than going through 'toList'.
 maximum
-    :: forall t a s. (Foldable t, Functor t, Backprop a, Ord a, Backprop (t a), Reifies s W)
+    :: (Foldable t, Functor t, Backprop a, Ord a, Backprop (t a), Reifies s W)
     => BVar s (t a)
     -> BVar s a
-maximum = liftOp1 . op1 $ \xs ->
-    let m = P.maximum xs
-    in  ( m
-        , \d -> (\x -> if x == m then d else zero x) P.<$> xs
-        )
+maximum = E.maximum E.addFunc E.zeroFunc
 {-# INLINE maximum #-}
 
 -- | Lifted 'P.fmap'.  Lifts backpropagatable functions to be
 -- backpropagatable functions on 'Traversable' 'Functor's.
 fmap
-    :: forall f a b s. (Traversable f, Backprop a, Backprop b, Backprop (f b), Reifies s W)
+    :: (Traversable f, Backprop a, Backprop b, Backprop (f b), Reifies s W)
     => (BVar s a -> BVar s b)
     -> BVar s (f a)
     -> BVar s (f b)
-fmap f = collectVar . P.fmap f . sequenceVar
+fmap = E.fmap E.addFunc E.addFunc E.zeroFunc E.zeroFunc E.zeroFunc
 {-# INLINE fmap #-}
 
 -- | Alias for 'fmap'.
 (<$>)
-    :: forall f a b s. (Traversable f, Backprop a, Backprop b, Backprop (f b), Reifies s W)
+    :: (Traversable f, Backprop a, Backprop b, Backprop (f b), Reifies s W)
     => (BVar s a -> BVar s b)
     -> BVar s (f a)
     -> BVar s (f b)
@@ -144,22 +122,18 @@
 -- | Lifted 'P.traverse'.  Lifts backpropagatable functions to be
 -- backpropagatable functions on 'Traversable' 'Functor's.
 traverse
-    :: forall t f a b s. (Traversable t, Applicative f, Foldable f, Backprop a, Backprop b, Backprop (f (t b)), Backprop (t b), Reifies s W)
+    :: (Traversable t, Applicative f, Foldable f, Backprop a, Backprop b, Backprop (f (t b)), Backprop (t b), Reifies s W)
     => (BVar s a -> f (BVar s b))
     -> BVar s (t a)
     -> BVar s (f (t b))
-traverse f = collectVar
-           . P.fmap collectVar
-           . P.traverse f
-           . sequenceVar
+traverse = E.traverse E.addFunc E.addFunc E.addFunc
+                      E.zeroFunc E.zeroFunc E.zeroFunc E.zeroFunc
 {-# INLINE traverse #-}
 
 -- | Lifted 'P.liftA2'.  Lifts backpropagatable functions to be
 -- backpropagatable functions on 'Traversable' 'Applicative's.
 liftA2
-    :: forall f a b c s.
-       ( Traversable f
-       , Applicative f
+    :: ( Traversable f, Applicative f
        , Backprop a, Backprop b, Backprop c, Backprop (f c)
        , Reifies s W
        )
@@ -167,15 +141,14 @@
     -> BVar s (f a)
     -> BVar s (f b)
     -> BVar s (f c)
-liftA2 f x y = collectVar $ f P.<$> sequenceVar x
-                              P.<*> sequenceVar y
+liftA2 = E.liftA2 E.addFunc E.addFunc E.addFunc
+                  E.zeroFunc E.zeroFunc E.zeroFunc E.zeroFunc
 {-# INLINE liftA2 #-}
 
 -- | Lifted 'P.liftA3'.  Lifts backpropagatable functions to be
 -- backpropagatable functions on 'Traversable' 'Applicative's.
 liftA3
-    :: forall f a b c d s.
-       ( Traversable f
+    :: ( Traversable f
        , Applicative f
        , Backprop a, Backprop b, Backprop c, Backprop d, Backprop (f d)
        , Reifies s W
@@ -185,19 +158,10 @@
     -> BVar s (f b)
     -> BVar s (f c)
     -> BVar s (f d)
-liftA3 f x y z = collectVar $ f P.<$> sequenceVar x
-                                P.<*> sequenceVar y
-                                P.<*> sequenceVar z
+liftA3 = E.liftA3 E.addFunc E.addFunc E.addFunc E.addFunc
+                  E.zeroFunc E.zeroFunc E.zeroFunc E.zeroFunc E.zeroFunc
 {-# INLINE liftA3 #-}
 
--- | Coerce items inside a 'BVar'.
-coerce
-    :: forall a b s. C.Coercible a b
-    => BVar s a
-    -> BVar s b
-coerce = coerceVar
-{-# INLINE coerce #-}
-
 -- | Lifted conversion between two 'P.Integral' instances.
 --
 -- @since 0.2.1.0
@@ -205,8 +169,7 @@
     :: (Backprop a, P.Integral a, Backprop b, P.Integral b, Reifies s W)
     => BVar s a
     -> BVar s b
-fromIntegral = liftOp1 . op1 $ \x ->
-    (P.fromIntegral x, P.fromIntegral)
+fromIntegral = E.fromIntegral E.addFunc E.zeroFunc
 {-# INLINE fromIntegral #-}
 
 -- | Lifted conversion between two 'Fractional' and 'P.Real' instances.
@@ -216,6 +179,46 @@
     :: (Backprop a, Fractional a, P.Real a, Backprop b, Fractional b, P.Real b, Reifies s W)
     => BVar s a
     -> BVar s b
-realToFrac = liftOp1 . op1 $ \x ->
-    (P.realToFrac x, P.realToFrac)
+realToFrac = E.realToFrac E.addFunc E.zeroFunc
 {-# INLINE realToFrac #-}
+
+-- | Lifted version of 'P.toList'.  Takes a 'BVar' of a 'Traversable' of
+-- items and returns a list of 'BVar's for each item.
+--
+-- You can use this to implement "lifted" versions of 'Foldable' methods
+-- like 'P.foldr', 'P.foldl'', etc.; however, 'sum', 'product', 'length',
+-- 'minimum', and 'maximum' have more efficient implementations than simply
+-- @'P.minimum' . 'toList'.@
+--
+-- @since 0.2.2.0
+toList
+    :: (Traversable t, Backprop a, Reifies s W)
+    => BVar s (t a)
+    -> [BVar s a]
+toList = E.toList E.addFunc E.zeroFunc
+{-# INLINE toList #-}
+
+-- | Lifted version of 'P.mapAccumL'.
+--
+-- @since 0.2.2.0
+mapAccumL
+    :: (Traversable t, Backprop b, Backprop c, Backprop (t c), Reifies s W)
+    => (BVar s a -> BVar s b -> (BVar s a, BVar s c))
+    -> BVar s a
+    -> BVar s (t b)
+    -> (BVar s a, BVar s (t c))
+mapAccumL = E.mapAccumL E.addFunc E.addFunc E.zeroFunc E.zeroFunc E.zeroFunc
+{-# INLINE mapAccumL #-}
+
+-- | Lifted version of 'P.mapAccumR'.
+--
+-- @since 0.2.2.0
+mapAccumR
+    :: (Traversable t, Backprop b, Backprop c, Backprop (t c), Reifies s W)
+    => (BVar s a -> BVar s b -> (BVar s a, BVar s c))
+    -> BVar s a
+    -> BVar s (t b)
+    -> (BVar s a, BVar s (t c))
+mapAccumR = E.mapAccumR E.addFunc E.addFunc E.zeroFunc E.zeroFunc E.zeroFunc
+{-# INLINE mapAccumR #-}
+
diff --git a/src/Prelude/Backprop/Explicit.hs b/src/Prelude/Backprop/Explicit.hs
--- a/src/Prelude/Backprop/Explicit.hs
+++ b/src/Prelude/Backprop/Explicit.hs
@@ -1,5 +1,5 @@
 {-# LANGUAGE FlexibleContexts    #-}
-{-# LANGUAGE ScopedTypeVariables #-}
+{-# OPTIONS_HADDOCK not-home     #-}
 
 -- |
 -- Module      : Prelude.Backprop.Explicit
@@ -24,6 +24,9 @@
   , minimum
   , maximum
   , traverse
+  , toList
+  , mapAccumL
+  , mapAccumR
   -- * Functor and Applicative
   , fmap
   , pure
@@ -35,15 +38,17 @@
   , coerce
   ) where
 
+import           Data.Bifunctor
 import           Numeric.Backprop.Explicit
-import           Prelude             (Num(..), Fractional(..), Eq(..), Ord(..), Functor, Foldable, Traversable, Applicative, (.), ($))
-import qualified Control.Applicative as P
-import qualified Data.Coerce         as C
-import qualified Data.Foldable       as P
-import qualified Prelude             as P
+import           Prelude                   (Num(..), Fractional(..), Eq(..), Ord(..), Functor, Foldable, Traversable, Applicative, (.), ($))
+import qualified Control.Applicative       as P
+import qualified Data.Coerce               as C
+import qualified Data.Foldable             as P
+import qualified Data.Traversable          as P
+import qualified Prelude                   as P
 
--- | Lifted 'P.sum'
-sum :: forall t a s. (Foldable t, Functor t, Num a, Reifies s W)
+-- | 'Prelude.Backprop.sum', but taking explicit 'add' and 'zero'.
+sum :: (Foldable t, Functor t, Num a, Reifies s W)
     => AddFunc (t a)
     -> ZeroFunc a
     -> BVar s (t a)
@@ -54,9 +59,9 @@
     )
 {-# INLINE sum #-}
 
--- | Lifted 'P.pure'.
+-- | 'Prelude.Backprop.pure', but taking explicit 'add' and 'zero'.
 pure
-    :: forall t a s. (Foldable t, Applicative t, Reifies s W)
+    :: (Foldable t, Applicative t, Reifies s W)
     => AddFunc a
     -> ZeroFunc a
     -> ZeroFunc (t a)
@@ -68,9 +73,9 @@
     )
 {-# INLINE pure #-}
 
--- | Lifted 'P.product'
+-- | 'Prelude.Backprop.product', but taking explicit 'add' and 'zero'.
 product
-    :: forall t a s. (Foldable t, Functor t, Fractional a, Reifies s W)
+    :: (Foldable t, Functor t, Fractional a, Reifies s W)
     => AddFunc (t a)
     -> ZeroFunc a
     -> BVar s (t a)
@@ -82,9 +87,9 @@
        )
 {-# INLINE product #-}
 
--- | Lifted 'P.length'.
+-- | 'Prelude.Backprop.length', but taking explicit 'add' and 'zero'.
 length
-    :: forall t a b s. (Foldable t, Num b, Reifies s W)
+    :: (Foldable t, Num b, Reifies s W)
     => AddFunc (t a)
     -> ZeroFunc (t a)
     -> ZeroFunc b
@@ -96,10 +101,9 @@
     )
 {-# INLINE length #-}
 
--- | Lifted 'P.minimum'.  Undefined for situations where 'P.minimum' would
--- be undefined.
+-- | 'Prelude.Backprop.minimum', but taking explicit 'add' and 'zero'.
 minimum
-    :: forall t a s. (Foldable t, Functor t, Ord a, Reifies s W)
+    :: (Foldable t, Functor t, Ord a, Reifies s W)
     => AddFunc (t a)
     -> ZeroFunc a
     -> BVar s (t a)
@@ -111,10 +115,9 @@
         )
 {-# INLINE minimum #-}
 
--- | Lifted 'P.maximum'.  Undefined for situations where 'P.maximum' would
--- be undefined.
+-- | 'Prelude.Backprop.maximum', but taking explicit 'add' and 'zero'.
 maximum
-    :: forall t a s. (Foldable t, Functor t, Ord a, Reifies s W)
+    :: (Foldable t, Functor t, Ord a, Reifies s W)
     => AddFunc (t a)
     -> ZeroFunc a
     -> BVar s (t a)
@@ -126,10 +129,9 @@
         )
 {-# INLINE maximum #-}
 
--- | Lifted 'P.fmap'.  Lifts backpropagatable functions to be
--- backpropagatable functions on 'Traversable' 'Functor's.
+-- | 'Prelude.Backprop.fmap', but taking explicit 'add' and 'zero'.
 fmap
-    :: forall f a b s. (Traversable f, Reifies s W)
+    :: (Traversable f, Reifies s W)
     => AddFunc a
     -> AddFunc b
     -> ZeroFunc a
@@ -141,10 +143,9 @@
 fmap afa afb zfa zfb zfbs f = collectVar afb zfb zfbs . P.fmap f . sequenceVar afa zfa
 {-# INLINE fmap #-}
 
--- | Lifted 'P.traverse'.  Lifts backpropagatable functions to be
--- backpropagatable functions on 'Traversable' 'Functor's.
+-- | 'Prelude.Backprop.traverse', but taking explicit 'add' and 'zero'.
 traverse
-    :: forall t f a b s. (Traversable t, Applicative f, Foldable f, Reifies s W)
+    :: (Traversable t, Applicative f, Foldable f, Reifies s W)
     => AddFunc a
     -> AddFunc b
     -> AddFunc (t b)
@@ -162,11 +163,9 @@
         . sequenceVar afa zfa
 {-# INLINE traverse #-}
 
--- | Lifted 'P.liftA2'.  Lifts backpropagatable functions to be
--- backpropagatable functions on 'Traversable' 'Applicative's.
+-- | 'Prelude.Backprop.liftA2', but taking explicit 'add' and 'zero'.
 liftA2
-    :: forall f a b c s.
-       ( Traversable f
+    :: ( Traversable f
        , Applicative f
        , Reifies s W
        )
@@ -187,11 +186,9 @@
         P.<*> sequenceVar afb zfb y
 {-# INLINE liftA2 #-}
 
--- | Lifted 'P.liftA3'.  Lifts backpropagatable functions to be
--- backpropagatable functions on 'Traversable' 'Applicative's.
+-- | 'Prelude.Backprop.liftA3', but taking explicit 'add' and 'zero'.
 liftA3
-    :: forall f a b c d s.
-       ( Traversable f
+    :: ( Traversable f
        , Applicative f
        , Reifies s W
        )
@@ -217,14 +214,11 @@
 {-# INLINE liftA3 #-}
 
 -- | Coerce items inside a 'BVar'.
-coerce
-    :: forall a b s. C.Coercible a b
-    => BVar s a
-    -> BVar s b
+coerce :: C.Coercible a b => BVar s a -> BVar s b
 coerce = coerceVar
 {-# INLINE coerce #-}
 
--- | Lifted conversion between two 'P.Integral' instances.
+-- | 'Prelude.Backprop.fromIntegral', but taking explicit 'add' and 'zero'.
 --
 -- @since 0.2.1.0
 fromIntegral
@@ -237,7 +231,7 @@
     (P.fromIntegral x, P.fromIntegral)
 {-# INLINE fromIntegral #-}
 
--- | Lifted conversion between two 'Fractional' and 'P.Real' instances.
+-- | 'Prelude.Backprop.realToFrac', but taking explicit 'add' and 'zero'.
 --
 -- @since 0.2.1.0
 realToFrac
@@ -249,3 +243,55 @@
 realToFrac af zf = liftOp1 af zf . op1 $ \x ->
     (P.realToFrac x, P.realToFrac)
 {-# INLINE realToFrac #-}
+
+-- | 'Prelude.Backprop.length', but taking explicit 'add' and 'zero'.
+--
+-- @since 0.2.2.0
+toList
+    :: (Traversable t, Reifies s W)
+    => AddFunc a
+    -> ZeroFunc a
+    -> BVar s (t a)
+    -> [BVar s a]
+toList af zf = toListOfVar af zf P.traverse
+{-# INLINE toList #-}
+
+-- | 'Prelude.Backprop.mapAccumL', but taking explicit 'add' and 'zero'.
+--
+-- @since 0.2.2.0
+mapAccumL
+    :: (Traversable t, Reifies s W)
+    => AddFunc b
+    -> AddFunc c
+    -> ZeroFunc b
+    -> ZeroFunc c
+    -> ZeroFunc (t c)
+    -> (BVar s a -> BVar s b -> (BVar s a, BVar s c))
+    -> BVar s a
+    -> BVar s (t b)
+    -> (BVar s a, BVar s (t c))
+mapAccumL afb afc zfb zfc zftc f s =
+        second (collectVar afc zfc zftc)
+      . P.mapAccumL f s
+      . sequenceVar afb zfb
+{-# INLINE mapAccumL #-}
+
+-- | 'Prelude.Backprop.mapAccumR', but taking explicit 'add' and 'zero'.
+--
+-- @since 0.2.2.0
+mapAccumR
+    :: (Traversable t, Reifies s W)
+    => AddFunc b
+    -> AddFunc c
+    -> ZeroFunc b
+    -> ZeroFunc c
+    -> ZeroFunc (t c)
+    -> (BVar s a -> BVar s b -> (BVar s a, BVar s c))
+    -> BVar s a
+    -> BVar s (t b)
+    -> (BVar s a, BVar s (t c))
+mapAccumR afb afc zfb zfc zftc f s =
+        second (collectVar afc zfc zftc)
+      . P.mapAccumR f s
+      . sequenceVar afb zfb
+{-# INLINE mapAccumR #-}
diff --git a/src/Prelude/Backprop/Num.hs b/src/Prelude/Backprop/Num.hs
--- a/src/Prelude/Backprop/Num.hs
+++ b/src/Prelude/Backprop/Num.hs
@@ -1,5 +1,5 @@
 {-# LANGUAGE FlexibleContexts    #-}
-{-# LANGUAGE ScopedTypeVariables #-}
+{-# OPTIONS_HADDOCK not-home     #-}
 
 -- |
 -- Module      : Prelude.Backprop.Num
@@ -23,6 +23,9 @@
   , minimum
   , maximum
   , traverse
+  , toList
+  , mapAccumL
+  , mapAccumR
   -- * Functor and Applicative
   , fmap
   , (<$>)
@@ -32,123 +35,101 @@
   -- * Misc
   , fromIntegral
   , realToFrac
-  , coerce
+  , E.coerce
   ) where
 
 import           Numeric.Backprop.Num
-import           Prelude              (Num(..), Fractional(..), Eq(..), Ord(..), Functor, Foldable, Traversable, Applicative, (.), ($))
-import qualified Control.Applicative  as P
-import qualified Data.Coerce          as C
-import qualified Data.Foldable        as P
-import qualified Prelude              as P
+import           Prelude                   (Num(..), Fractional(..), Ord(..), Functor, Foldable, Traversable, Applicative)
+import qualified Numeric.Backprop.Explicit as E
+import qualified Prelude                   as P
+import qualified Prelude.Backprop.Explicit as E
 
--- | Lifted 'P.sum'
-sum :: forall t a s. (Foldable t, Functor t, Num (t a), Num a, Reifies s W)
+-- | 'Prelude.Backprop.sum', but with 'Num' constraints instead of
+-- 'Backprop' constraints.
+sum :: (Foldable t, Functor t, Num (t a), Num a, Reifies s W)
     => BVar s (t a)
     -> BVar s a
-sum = liftOp1 . op1 $ \xs ->
-    ( P.sum xs
-    , (P.<$ xs)
-    )
+sum = E.sum E.afNum E.zfNum
 {-# INLINE sum #-}
 
--- | Lifted 'P.pure'.
+-- | 'Prelude.Backprop.pure', but with 'Num' constraints instead of
+-- 'Backprop' constraints.
 pure
-    :: forall t a s. (Foldable t, Applicative t, Num (t a), Num a, Reifies s W)
+    :: (Foldable t, Applicative t, Num (t a), Num a, Reifies s W)
     => BVar s a
     -> BVar s (t a)
-pure = liftOp1 . op1 $ \x ->
-    ( P.pure x
-    , P.sum
-    )
+pure = E.pure E.afNum E.zfNum E.zfNum
 {-# INLINE pure #-}
 
--- | Lifted 'P.product'
+-- | 'Prelude.Backprop.product', but with 'Num' constraints instead of
+-- 'Backprop' constraints.
 product
-    :: forall t a s. (Foldable t, Functor t, Num (t a), Fractional a, Reifies s W)
+    :: (Foldable t, Functor t, Num (t a), Fractional a, Reifies s W)
     => BVar s (t a)
     -> BVar s a
-product = liftOp1 . op1 $ \xs ->
-    let p = P.product xs
-    in ( p
-       , \d -> (\x -> p * d / x) P.<$> xs
-       )
+product = E.product E.afNum E.zfNum
 {-# INLINE product #-}
 
--- | Lifted 'P.length'.
+-- | 'Prelude.Backprop.length', but with 'Num' constraints instead of
+-- 'Backprop' constraints.
 length
-    :: forall t a b s. (Foldable t, Num (t a), Num b, Reifies s W)
+    :: (Foldable t, Num (t a), Num b, Reifies s W)
     => BVar s (t a)
     -> BVar s b
-length = liftOp1 . op1 $ \xs ->
-    ( P.fromIntegral (P.length xs)
-    , P.const 0
-    )
+length = E.length E.afNum E.zfNum E.zfNum
 {-# INLINE length #-}
 
--- | Lifted 'P.minimum'.  Undefined for situations where 'P.minimum' would
--- be undefined.
+-- | 'Prelude.Backprop.minimum', but with 'Num' constraints instead of
+-- 'Backprop' constraints.
 minimum
-    :: forall t a s. (Foldable t, Functor t, Num a, Ord a, Num (t a), Reifies s W)
+    :: (Foldable t, Functor t, Num a, Ord a, Num (t a), Reifies s W)
     => BVar s (t a)
     -> BVar s a
-minimum = liftOp1 . op1 $ \xs ->
-    let m = P.minimum xs
-    in  ( m
-        , \d -> (\x -> if x == m then d else 0) P.<$> xs
-        )
+minimum = E.minimum E.afNum E.zfNum
 {-# INLINE minimum #-}
 
--- | Lifted 'P.maximum'.  Undefined for situations where 'P.maximum' would
--- be undefined.
+-- | 'Prelude.Backprop.maximum', but with 'Num' constraints instead of
+-- 'Backprop' constraints.
 maximum
-    :: forall t a s. (Foldable t, Functor t, Num a, Ord a, Num (t a), Reifies s W)
+    :: (Foldable t, Functor t, Num a, Ord a, Num (t a), Reifies s W)
     => BVar s (t a)
     -> BVar s a
-maximum = liftOp1 . op1 $ \xs ->
-    let m = P.maximum xs
-    in  ( m
-        , \d -> (\x -> if x == m then d else 0) P.<$> xs
-        )
+maximum = E.maximum E.afNum E.zfNum
 {-# INLINE maximum #-}
 
--- | Lifted 'P.fmap'.  Lifts backpropagatable functions to be
--- backpropagatable functions on 'Traversable' 'Functor's.
+-- | 'Prelude.Backprop.fmap', but with 'Num' constraints instead of
+-- 'Backprop' constraints.
 fmap
-    :: forall f a b s. (Traversable f, Num a, Num b, Num (f b), Reifies s W)
+    :: (Traversable f, Num a, Num b, Num (f b), Reifies s W)
     => (BVar s a -> BVar s b)
     -> BVar s (f a)
     -> BVar s (f b)
-fmap f = collectVar . P.fmap f . sequenceVar
+fmap = E.fmap E.afNum E.afNum E.zfNum E.zfNum E.zfNum
 {-# INLINE fmap #-}
 
 -- | Alias for 'fmap'.
 (<$>)
-    :: forall f a b s. (Traversable f, Num a, Num b, Num (f b), Reifies s W)
+    :: (Traversable f, Num a, Num b, Num (f b), Reifies s W)
     => (BVar s a -> BVar s b)
     -> BVar s (f a)
     -> BVar s (f b)
 (<$>) = fmap
 {-# INLINE (<$>) #-}
 
--- | Lifted 'P.traverse'.  Lifts backpropagatable functions to be
--- backpropagatable functions on 'Traversable' 'Functor's.
+-- | 'Prelude.Backprop.traverse', but with 'Num' constraints instead of
+-- 'Backprop' constraints.
 traverse
-    :: forall t f a b s. (Traversable t, Applicative f, Foldable f, Num a, Num b, Num (f (t b)), Num (t b), Reifies s W)
+    :: (Traversable t, Applicative f, Foldable f, Num a, Num b, Num (f (t b)), Num (t b), Reifies s W)
     => (BVar s a -> f (BVar s b))
     -> BVar s (t a)
     -> BVar s (f (t b))
-traverse f = collectVar
-           . P.fmap collectVar
-           . P.traverse f
-           . sequenceVar
+traverse = E.traverse E.afNum E.afNum E.afNum E.zfNum E.zfNum E.zfNum E.zfNum
 {-# INLINE traverse #-}
 
--- | Lifted 'P.liftA2'.  Lifts backpropagatable functions to be
--- backpropagatable functions on 'Traversable' 'Applicative's.
+-- | 'Prelude.Backprop.liftA2', but with 'Num' constraints instead of
+-- 'Backprop' constraints.
 liftA2
-    :: forall f a b c s.
-       ( Traversable f
+    :: ( Traversable f
        , Applicative f
        , Num a, Num b, Num c, Num (f c)
        , Reifies s W
@@ -157,15 +138,13 @@
     -> BVar s (f a)
     -> BVar s (f b)
     -> BVar s (f c)
-liftA2 f x y = collectVar $ f P.<$> sequenceVar x
-                              P.<*> sequenceVar y
+liftA2 = E.liftA2 E.afNum E.afNum E.afNum E.zfNum E.zfNum E.zfNum E.zfNum
 {-# INLINE liftA2 #-}
 
--- | Lifted 'P.liftA3'.  Lifts backpropagatable functions to be
--- backpropagatable functions on 'Traversable' 'Applicative's.
+-- | 'Prelude.Backprop.liftA3', but with 'Num' constraints instead of
+-- 'Backprop' constraints.
 liftA3
-    :: forall f a b c d s.
-       ( Traversable f
+    :: ( Traversable f
        , Applicative f
        , Num a, Num b, Num c, Num d, Num (f d)
        , Reifies s W
@@ -175,37 +154,66 @@
     -> BVar s (f b)
     -> BVar s (f c)
     -> BVar s (f d)
-liftA3 f x y z = collectVar $ f P.<$> sequenceVar x
-                                P.<*> sequenceVar y
-                                P.<*> sequenceVar z
+liftA3 = E.liftA3 E.afNum E.afNum E.afNum E.afNum
+                  E.zfNum E.zfNum E.zfNum E.zfNum E.zfNum
 {-# INLINE liftA3 #-}
 
--- | Coerce items inside a 'BVar'.
-coerce
-    :: forall a b s. C.Coercible a b
-    => BVar s a
-    -> BVar s b
-coerce = coerceVar
-{-# INLINE coerce #-}
-
--- | Lifted conversion between two 'P.Integral' instances.
+-- | 'Prelude.Backprop.fromIntegral', but with 'Num' constraints instead of
+-- 'Backprop' constraints.
 --
 -- @since 0.2.1.0
 fromIntegral
     :: (P.Integral a, P.Integral b, Reifies s W)
     => BVar s a
     -> BVar s b
-fromIntegral = liftOp1 . op1 $ \x ->
-    (P.fromIntegral x, P.fromIntegral)
+fromIntegral = E.fromIntegral E.afNum E.zfNum
 {-# INLINE fromIntegral #-}
 
--- | Lifted conversion between two 'Fractional' and 'P.Real' instances.
+-- | 'Prelude.Backprop.realToFrac', but with 'Num' constraints instead of
+-- 'Backprop' constraints.
 --
 -- @since 0.2.1.0
 realToFrac
     :: (Fractional a, P.Real a, Fractional b, P.Real b, Reifies s W)
     => BVar s a
     -> BVar s b
-realToFrac = liftOp1 . op1 $ \x ->
-    (P.realToFrac x, P.realToFrac)
+realToFrac = E.realToFrac E.afNum E.zfNum
 {-# INLINE realToFrac #-}
+
+-- | 'Prelude.Backprop.toList', but with 'Num' constraints instead of
+-- 'Backprop' constraints.
+--
+-- @since 0.2.2.0
+toList
+    :: (Traversable t, Num a, Reifies s W)
+    => BVar s (t a)
+    -> [BVar s a]
+toList = E.toList E.afNum E.zfNum
+{-# INLINE toList #-}
+
+-- | 'Prelude.Backprop.mapAccumL', but with 'Num' constraints instead of
+-- 'Backprop' constraints.
+--
+-- @since 0.2.2.0
+mapAccumL
+    :: (Traversable t, Num b, Num c, Num (t c), Reifies s W)
+    => (BVar s a -> BVar s b -> (BVar s a, BVar s c))
+    -> BVar s a
+    -> BVar s (t b)
+    -> (BVar s a, BVar s (t c))
+mapAccumL = E.mapAccumL E.afNum E.afNum E.zfNum E.zfNum E.zfNum
+{-# INLINE mapAccumL #-}
+
+-- | 'Prelude.Backprop.mapAccumR', but with 'Num' constraints instead of
+-- 'Backprop' constraints.
+--
+-- @since 0.2.2.0
+mapAccumR
+    :: (Traversable t, Num b, Num c, Num (t c), Reifies s W)
+    => (BVar s a -> BVar s b -> (BVar s a, BVar s c))
+    -> BVar s a
+    -> BVar s (t b)
+    -> (BVar s a, BVar s (t c))
+mapAccumR = E.mapAccumR E.afNum E.afNum E.zfNum E.zfNum E.zfNum
+{-# INLINE mapAccumR #-}
+
