diff --git a/Numeric/AD.hs b/Numeric/AD.hs
--- a/Numeric/AD.hs
+++ b/Numeric/AD.hs
@@ -16,41 +16,49 @@
 module Numeric.AD
     (
     -- * Gradients
-      grad, grad2
-    , gradWith, gradWith2
+      grad, grad'
+    , gradWith, gradWith'
 
     -- * Jacobians
-    , jacobian, jacobian2
-    , jacobianWith, jacobianWith2
-
-    -- * Synonyms
-    , diff
-    , diff2
-    , diffs
-    , diffs0
+    , jacobian, jacobian'
+    , jacobianWith, jacobianWith'
 
     -- * Derivatives (Forward)
-    , diffUU
-    , diffUF
-
-    , diff2UU
-    , diff2UF
+    , diff
+    , diffF
 
-    -- * Derivatives (Reverse)
-    , diffFU
-    , diff2FU
+    , diff'
+    , diffF'
 
     -- * Derivatives (Tower)
-    , diffsUU
-    , diffsUF
+    , diffs
+    , diffsF
 
-    , diffs0UU
-    , diffs0UF
+    , diffs0
+    , diffs0F
 
+    -- * Directional Derivatives (Forward)
+    , du
+    , du'
+    , duF
+    , duF'
+
     -- * Taylor Series (Tower)
     , taylor
     , taylor0
+    , maclaurin
+    , maclaurin0
 
+    -- * Monadic Combinators (Forward)
+    , diffM
+    , diffM'
+
+    -- * Monadic Combinators (Reverse)
+    , gradM
+    , gradM'
+    , gradWithM
+    , gradWithM'
+
     -- * Exposed Types
     , AD(..)
     , Mode(..)
@@ -61,50 +69,59 @@
 import Control.Applicative
 import Numeric.AD.Classes  (Mode(..))
 import Numeric.AD.Internal (AD(..), probed, unprobe)
-import Numeric.AD.Forward  (diff, diffUU, diff2, diff2UU, diffUF, diff2UF)
-import Numeric.AD.Tower    (diffsUU, diffs0UU , diffsUF, diffs0UF , diffs, diffs0, taylor, taylor0)
-import Numeric.AD.Reverse  (diffFU, diff2FU, grad, grad2, gradWith, gradWith2)
+import Numeric.AD.Forward  (diff, diff', diffF, diffF', du, du', duF, duF', diffM, diffM') 
+import Numeric.AD.Tower    (diffsF, diffs0F , diffs, diffs0, taylor, taylor0, maclaurin, maclaurin0)
+import Numeric.AD.Reverse  (grad, grad', gradWith, gradWith', gradM, gradM', gradWithM, gradWithM')
 
 import qualified Numeric.AD.Forward as Forward
 import qualified Numeric.AD.Reverse as Reverse
 
--- | Calculate the Jacobian of a non-scalar-to-non-scalar function, automatically choosing between forward and reverse mode AD based on the number of inputs and outputs
+-- | Calculate the Jacobian of a non-scalar-to-non-scalar function, automatically choosing between forward and reverse mode AD based on the number of inputs and outputs.
+--
+-- If you need to support functions where the output is only a 'Functor' or 'Monad', consider 'Numeric.AD.Reverse.jacobian' or 'Numeric.AD.Reverse.gradM' from "Numeric.AD.Reverse".
 jacobian :: (Traversable f, Traversable g, Num a) => (forall s. Mode s => f (AD s a) -> g (AD s a)) -> f a -> g (f a)
-jacobian f bs = snd <$> jacobian2 f bs
+jacobian f bs = snd <$> jacobian' f bs
 {-# INLINE jacobian #-}
 
--- | Calculate the answer and Jacobian of a non-scalar-to-non-scalar function, automatically choosing between forward- and reverse- mode AD based on the relative, number of inputs and outputs. If you need to support functions where the output is only a 'Functor', consider using 'jacobianT' from "Numeric.AD.Forward" or 'jacobian2' from "Numeric.AD.Reverse" directly.
-jacobian2 :: (Traversable f, Traversable g, Num a) => (forall s. Mode s => f (AD s a) -> g (AD s a)) -> f a -> g (a, f a)
-jacobian2 f bs | n == 0    = fmap (\x -> (unprobe x, bs)) as
-               | n > m     = Reverse.jacobian2 f bs
-               | otherwise = Forward.jacobian2 f bs
+-- | Calculate both the answer and Jacobian of a non-scalar-to-non-scalar function, automatically choosing between forward- and reverse- mode AD based on the relative, number of inputs and outputs.
+--
+-- If you need to support functions where the output is only a 'Functor' or 'Monad', consider 'Numeric.AD.Reverse.jacobian'' or 'Numeric.AD.Reverse.gradM'' from "Numeric.AD.Reverse".
+jacobian' :: (Traversable f, Traversable g, Num a) => (forall s. Mode s => f (AD s a) -> g (AD s a)) -> f a -> g (a, f a)
+jacobian' f bs | n == 0    = fmap (\x -> (unprobe x, bs)) as
+               | n > m     = Reverse.jacobian' f bs
+               | otherwise = Forward.jacobian' f bs
     where
         as = f (probed bs)
         n = size bs
         m = size as
         size :: Foldable f => f a -> Int
         size = foldr' (\_ b -> 1 + b) 0
-{-# INLINE jacobian2 #-}
+{-# INLINE jacobian' #-}
 
 -- | @'jacobianWith' g f@ calculates the Jacobian of a non-scalar-to-non-scalar function, automatically choosing between forward and reverse mode AD based on the number of inputs and outputs.
--- 
--- The resulting Jacobian matrix is then recombined element-wise with the input using @g@. 
+--
+-- The resulting Jacobian matrix is then recombined element-wise with the input using @g@.
+--
+-- If you need to support functions where the output is only a 'Functor' or 'Monad', consider 'Numeric.AD.Reverse.jacobianWith' or 'Numeric.AD.Reverse.gradWithM' from "Numeric.AD.Reverse".
 jacobianWith :: (Traversable f, Traversable g, Num a) => (a -> a -> b) -> (forall s. Mode s => f (AD s a) -> g (AD s a)) -> f a -> g (f b)
-jacobianWith g f bs = snd <$> jacobianWith2 g f bs
+jacobianWith g f bs = snd <$> jacobianWith' g f bs
 {-# INLINE jacobianWith #-}
 
--- | @'jacobianWith2' g f@ calculates the answer and Jacobian of a non-scalar-to-non-scalar function, automatically choosing between forward and reverse mode AD based on the number of inputs and outputs.
+-- | @'jacobianWith'' g f@ calculates the answer and Jacobian of a non-scalar-to-non-scalar function, automatically choosing between forward and reverse mode AD based on the number of inputs and outputs.
 --
--- The resulting Jacobian matrix is then recombined element-wise with the input using @g@. 
-jacobianWith2 :: (Traversable f, Traversable g, Num a) => (a -> a -> b) -> (forall s. Mode s => f (AD s a) -> g (AD s a)) -> f a -> g (a, f b)
-jacobianWith2 g f bs 
+-- The resulting Jacobian matrix is then recombined element-wise with the input using @g@.
+--
+-- If you need to support functions where the output is only a 'Functor' or 'Monad', consider 'Numeric.AD.Reverse.jacobianWith'' or 'Numeric.AD.Reverse.gradWithM'' from "Numeric.AD.Reverse".
+jacobianWith' :: (Traversable f, Traversable g, Num a) => (a -> a -> b) -> (forall s. Mode s => f (AD s a) -> g (AD s a)) -> f a -> g (a, f b)
+jacobianWith' g f bs
     | n == 0    = fmap (\x -> (unprobe x, undefined <$> bs)) as
-    | n > m     = Reverse.jacobianWith2 g f bs
-    | otherwise = Forward.jacobianWith2 g f bs
+    | n > m     = Reverse.jacobianWith' g f bs
+    | otherwise = Forward.jacobianWith' g f bs
     where
         as = f (probed bs)
         n = size bs
         m = size as
         size :: Foldable f => f a -> Int
         size = foldr' (\_ b -> 1 + b) 0
-{-# INLINE jacobianWith2 #-}
+{-# INLINE jacobianWith' #-}
+
diff --git a/Numeric/AD/Directed.hs b/Numeric/AD/Directed.hs
--- a/Numeric/AD/Directed.hs
+++ b/Numeric/AD/Directed.hs
@@ -14,18 +14,15 @@
 
 module Numeric.AD.Directed
     (
-    -- * Derivatives
-      diffUU
-    , diff2UU
-    -- * Common access patterns
-    , diff
-    , diff2
+    -- * Gradients
+      grad
+    , grad'
     -- * Jacobians
     , jacobian
-    , jacobian2
-    -- * Gradients
-    , grad
-    , grad2
+    , jacobian'
+    -- * Derivatives
+    , diff
+    , diff'
     -- * Exposed Types
     , Direction(..)
     , Mode(..)
@@ -51,53 +48,45 @@
     | Mixed
     deriving (Show, Eq, Ord, Read, Bounded, Enum, Ix)
 
-diffUU :: Num a => Direction -> (forall s. Mode s => AD s a -> AD s a) -> a -> a
-diffUU Forward = F.diffUU
-diffUU Reverse = R.diffUU
-diffUU Tower = T.diffUU
-diffUU Mixed = F.diffUU
-{-# INLINE diffUU #-}
-
-diff2UU :: Num a => Direction -> (forall s. Mode s => AD s a -> AD s a) -> a -> (a, a)
-diff2UU Forward = F.diff2UU
-diff2UU Reverse = R.diff2UU
-diff2UU Tower = T.diff2UU
-diff2UU Mixed = F.diff2UU
-{-# INLINE diff2UU #-}
-
 diff :: Num a => Direction -> (forall s. Mode s => AD s a -> AD s a) -> a -> a
-diff = diffUU
+diff Forward = F.diff
+diff Reverse = R.diff
+diff Tower = T.diff
+diff Mixed = F.diff
 {-# INLINE diff #-}
 
-diff2 :: Num a => Direction -> (forall s. Mode s => AD s a -> AD s a) -> a -> (a, a)
-diff2 = diff2UU
-{-# INLINE diff2 #-}
+diff' :: Num a => Direction -> (forall s. Mode s => AD s a -> AD s a) -> a -> (a, a)
+diff' Forward = F.diff'
+diff' Reverse = R.diff'
+diff' Tower = T.diff'
+diff' Mixed = F.diff'
+{-# INLINE diff' #-}
 
 jacobian :: (Traversable f, Traversable g, Num a) => Direction -> (forall s. Mode s => f (AD s a) -> g (AD s a)) -> f a -> g (f a)
 jacobian Forward = F.jacobian
 jacobian Reverse = R.jacobian
-jacobian Tower = error "jacobian Tower: unimplemented"
+jacobian Tower = F.jacobian -- error "jacobian Tower: unimplemented"
 jacobian Mixed = M.jacobian
 {-# INLINE jacobian #-}
 
-jacobian2 :: (Traversable f, Traversable g, Num a) => Direction -> (forall s. Mode s => f (AD s a) -> g (AD s a)) -> f a -> g (a, f a)
-jacobian2 Forward = F.jacobian2
-jacobian2 Reverse = R.jacobian2
-jacobian2 Tower = error "jacobian2 Tower: unimplemented"
-jacobian2 Mixed = M.jacobian2
-{-# INLINE jacobian2 #-}
+jacobian' :: (Traversable f, Traversable g, Num a) => Direction -> (forall s. Mode s => f (AD s a) -> g (AD s a)) -> f a -> g (a, f a)
+jacobian' Forward = F.jacobian'
+jacobian' Reverse = R.jacobian'
+jacobian' Tower = F.jacobian' -- error "jacobian' Tower: unimplemented"
+jacobian' Mixed = M.jacobian'
+{-# INLINE jacobian' #-}
 
 grad :: (Traversable f, Num a) => Direction -> (forall s. Mode s => f (AD s a) -> AD s a) -> f a -> f a
 grad Forward = F.grad
 grad Reverse = R.grad
-grad Tower   = error "grad Tower: unimplemented"
+grad Tower   = F.grad -- error "grad Tower: unimplemented"
 grad Mixed   = M.grad
 {-# INLINE grad #-}
 
-grad2 :: (Traversable f, Num a) => Direction -> (forall s. Mode s => f (AD s a) -> AD s a) -> f a -> (a, f a)
-grad2 Forward = F.grad2
-grad2 Reverse = R.grad2
-grad2 Tower   = error "grad2 Tower: unimplemented"
-grad2 Mixed   = M.grad2
-{-# INLINE grad2 #-}
+grad' :: (Traversable f, Num a) => Direction -> (forall s. Mode s => f (AD s a) -> AD s a) -> f a -> (a, f a)
+grad' Forward = F.grad'
+grad' Reverse = R.grad'
+grad' Tower   = F.grad' -- error "grad' Tower: unimplemented"
+grad' Mixed   = M.grad'
+{-# INLINE grad' #-}
 
diff --git a/Numeric/AD/Forward.hs b/Numeric/AD/Forward.hs
--- a/Numeric/AD/Forward.hs
+++ b/Numeric/AD/Forward.hs
@@ -16,27 +16,30 @@
     (
     -- * Gradient
       grad
-    , grad2
+    , grad'
     , gradWith
-    , gradWith2
+    , gradWith'
     -- * Jacobian
     , jacobian
-    , jacobian2
-    , jacobianT
+    , jacobian'
     , jacobianWith
-    , jacobianWith2
+    , jacobianWith'
+    -- * Transposed Jacobian
+    , jacobianT
     , jacobianWithT
     -- * Derivatives
-    , diffUU
-    , diff2UU
-    , diffUF
-    , diff2UF
-    -- * Directional Derivatives
-    , diffMU 
-    , diff2MU
-    -- * Synonyms
     , diff
-    , diff2
+    , diff'
+    , diffF
+    , diffF'
+    -- * Directional Derivatives
+    , du
+    , du'
+    , duF
+    , duF'
+    -- * Monadic Combinators
+    , diffM
+    , diffM'
     -- * Exposed Types
     , AD(..)
     , Mode(..)
@@ -44,103 +47,115 @@
 
 import Data.Traversable (Traversable)
 import Control.Applicative
+import Control.Monad (liftM)
 import Numeric.AD.Classes
 import Numeric.AD.Internal
 import Numeric.AD.Internal.Forward
 
-diffMU :: (Functor f, Num a) => (forall s. Mode s => f (AD s a) -> AD s a) -> f (a, a) -> a
-diffMU f = tangent . f . fmap (uncurry bundle)
-{-# INLINE diffMU #-}
+du :: (Functor f, Num a) => (forall s. Mode s => f (AD s a) -> AD s a) -> f (a, a) -> a
+du f = tangent . f . fmap (uncurry bundle)
+{-# INLINE du #-}
 
-diff2MU :: (Functor f, Num a) => (forall s. Mode s => f (AD s a) -> AD s a) -> f (a, a) -> (a, a)
-diff2MU f = unbundle . f . fmap (uncurry bundle)
-{-# INLINE diff2MU #-}
+du' :: (Functor f, Num a) => (forall s. Mode s => f (AD s a) -> AD s a) -> f (a, a) -> (a, a)
+du' f = unbundle . f . fmap (uncurry bundle)
+{-# INLINE du' #-}
 
--- | The 'diff2' function calculates the first derivative of scalar-to-scalar function by 'Forward' 'AD'
+duF :: (Functor f, Functor g, Num a) => (forall s. Mode s => f (AD s a) -> g (AD s a)) -> f (a, a) -> g a
+duF f = fmap tangent . f . fmap (uncurry bundle)
+{-# INLINE duF #-}
+
+duF' :: (Functor f, Functor g, Num a) => (forall s. Mode s => f (AD s a) -> g (AD s a)) -> f (a, a) -> g (a, a)
+duF' f = fmap unbundle . f . fmap (uncurry bundle)
+{-# INLINE duF' #-}
+
+-- | The 'diff' function calculates the first derivative of a scalar-to-scalar function by forward-mode 'AD'
+--
+-- > diff sin == cos
 diff :: Num a => (forall s. Mode s => AD s a -> AD s a) -> a -> a
-diff = diffUU
+diff f a = tangent $ apply f a
 {-# INLINE diff #-}
 
--- | The 'diff2' function calculates the result and first derivative of scalar-to-scalar function by 'Forward' 'AD'
-diff2 :: Num a => (forall s. Mode s => AD s a -> AD s a) -> a -> (a, a)
-diff2 = diff2UU
-{-# INLINE diff2 #-}
+-- | The 'd'UU' function calculates the result and first derivative of scalar-to-scalar function by F'orward' 'AD'
+-- 
+-- > d' sin == sin &&& cos
+-- > d' f = f &&& d f
+diff' :: Num a => (forall s. Mode s => AD s a -> AD s a) -> a -> (a, a)
+diff' f a = unbundle $ apply f a
+{-# INLINE diff' #-}
 
--- | The 'diffUU' function calculates the first derivative of a scalar-to-scalar function by 'Forward' 'AD'
-diffUU :: Num a => (forall s. Mode s => AD s a -> AD s a) -> a -> a
-diffUU f a = tangent $ apply f a
-{-# INLINE diffUU #-}
+-- | The 'diffF' function calculates the first derivative of scalar-to-nonscalar function by F'orward' 'AD'
+diffF :: (Functor f, Num a) => (forall s. Mode s => AD s a -> f (AD s a)) -> a -> f a
+diffF f a = tangent <$> apply f a
+{-# INLINE diffF #-}
 
--- | The 'diff2UU' function calculates the result and first derivative of scalar-to-scalar function by 'Forward' 'AD'
-diff2UU :: Num a => (forall s. Mode s => AD s a -> AD s a) -> a -> (a, a)
-diff2UU f a = unbundle $ apply f a
-{-# INLINE diff2UU #-}
+-- | The 'diffF'' function calculates the result and first derivative of a scalar-to-non-scalar function by F'orward' 'AD'
+diffF' :: (Functor f, Num a) => (forall s. Mode s => AD s a -> f (AD s a)) -> a -> f (a, a)
+diffF' f a = unbundle <$> apply f a
+{-# INLINE diffF' #-}
 
--- | The 'diffUF' function calculates the first derivative of scalar-to-nonscalar function by 'Forward' 'AD'
-diffUF :: (Functor f, Num a) => (forall s. Mode s => AD s a -> f (AD s a)) -> a -> f a
-diffUF f a = tangent <$> apply f a
-{-# INLINE diffUF #-}
+-- | The 'dUM' function calculates the first derivative of scalar-to-scalar monadic function by F'orward' 'AD'
+diffM :: (Monad m, Num a) => (forall s. Mode s => AD s a -> m (AD s a)) -> a -> m a
+diffM f a = tangent `liftM` apply f a
+{-# INLINE diffM #-}
 
--- | The 'diff2UF' function calculates the result and first derivative of a scalar-to-non-scalar function by 'Forward' 'AD'
-diff2UF :: (Functor f, Num a) => (forall s. Mode s => AD s a -> f (AD s a)) -> a -> f (a, a)
-diff2UF f a = unbundle <$> apply f a
-{-# INLINE diff2UF #-}
+-- | The 'd'UM' function calculates the result and first derivative of a scalar-to-scalar monadic function by F'orward' 'AD'
+diffM' :: (Monad m, Num a) => (forall s. Mode s => AD s a -> m (AD s a)) -> a -> m (a, a)
+diffM' f a = unbundle `liftM` apply f a
+{-# INLINE diffM' #-}
 
 -- | A fast, simple transposed Jacobian computed with forward-mode AD.
 jacobianT :: (Traversable f, Functor g, Num a) => (forall s. Mode s => f (AD s a) -> g (AD s a)) -> f a -> f (g a)
 jacobianT f = bind (fmap tangent . f)
--- jacobianT f as = fmap tangent <$> bind f as
 {-# INLINE jacobianT #-}
 
 -- | A fast, simple transposed Jacobian computed with forward-mode AD.
 jacobianWithT :: (Traversable f, Functor g, Num a) => (a -> a -> b) -> (forall s. Mode s => f (AD s a) -> g (AD s a)) -> f a -> f (g b)
-jacobianWithT g f = bindWith g' f 
-    where g' a ga = g a . tangent <$> ga 
+jacobianWithT g f = bindWith g' f
+    where g' a ga = g a . tangent <$> ga
 {-# INLINE jacobianWithT #-}
 
 jacobian :: (Traversable f, Traversable g, Num a) => (forall s. Mode s => f (AD s a) -> g (AD s a)) -> f a -> g (f a)
 jacobian f as = transposeWith (const id) t p
     where
-        (p, t) = bind2 (fmap tangent . f) as
+        (p, t) = bind' (fmap tangent . f) as
 {-# INLINE jacobian #-}
 
 jacobianWith :: (Traversable f, Traversable g, Num a) => (a -> a -> b) -> (forall s. Mode s => f (AD s a) -> g (AD s a)) -> f a -> g (f b)
 jacobianWith g f as = transposeWith (const id) t p
     where
-        (p, t) = bindWith2 g' f as
-        g' a ga = g a . tangent <$> ga 
+        (p, t) = bindWith' g' f as
+        g' a ga = g a . tangent <$> ga
 {-# INLINE jacobianWith #-}
 
-jacobian2 :: (Traversable f, Traversable g, Num a) => (forall s. Mode s => f (AD s a) -> g (AD s a)) -> f a -> g (a, f a)
-jacobian2 f as = transposeWith row t p
+jacobian' :: (Traversable f, Traversable g, Num a) => (forall s. Mode s => f (AD s a) -> g (AD s a)) -> f a -> g (a, f a)
+jacobian' f as = transposeWith row t p
     where
-        (p, t) = bind2 f as
+        (p, t) = bind' f as
         row x as' = (primal x, tangent <$> as')
-{-# INLINE jacobian2 #-}
+{-# INLINE jacobian' #-}
 
-jacobianWith2 :: (Traversable f, Traversable g, Num a) => (a -> a -> b) -> (forall s. Mode s => f (AD s a) -> g (AD s a)) -> f a -> g (a, f b)
-jacobianWith2 g f as = transposeWith row t p
+jacobianWith' :: (Traversable f, Traversable g, Num a) => (a -> a -> b) -> (forall s. Mode s => f (AD s a) -> g (AD s a)) -> f a -> g (a, f b)
+jacobianWith' g f as = transposeWith row t p
     where
-        (p, t) = bindWith2 g' f as
+        (p, t) = bindWith' g' f as
         row x as' = (primal x, as')
-        g' a ga = g a . tangent <$> ga 
-{-# INLINE jacobianWith2 #-}
+        g' a ga = g a . tangent <$> ga
+{-# INLINE jacobianWith' #-}
 
 grad :: (Traversable f, Num a) => (forall s. Mode s => f (AD s a) -> AD s a) -> f a -> f a
 grad f = bind (tangent . f)
 {-# INLINE grad #-}
 
-
-grad2 :: (Traversable f, Num a) => (forall s. Mode s => f (AD s a) -> AD s a) -> f a -> (a, f a)
-grad2 f as = (primal b, tangent <$> bs)
+grad' :: (Traversable f, Num a) => (forall s. Mode s => f (AD s a) -> AD s a) -> f a -> (a, f a)
+grad' f as = (primal b, tangent <$> bs)
     where
-        (b, bs) = bind2 f as
-{-# INLINE grad2 #-}
+        (b, bs) = bind' f as
+{-# INLINE grad' #-}
 
 gradWith :: (Traversable f, Num a) => (a -> a -> b) -> (forall s. Mode s => f (AD s a) -> AD s a) -> f a -> f b
 gradWith g f = bindWith g (tangent . f)
 {-# INLINE gradWith #-}
 
-gradWith2 :: (Traversable f, Num a) => (a -> a -> b) -> (forall s. Mode s => f (AD s a) -> AD s a) -> f a -> (a, f b)
-gradWith2 g f = bindWith2 g (tangent . f)
-{-# INLINE gradWith2 #-}
+gradWith' :: (Traversable f, Num a) => (a -> a -> b) -> (forall s. Mode s => f (AD s a) -> AD s a) -> f a -> (a, f b)
+gradWith' g f = bindWith' g (tangent . f)
+{-# INLINE gradWith' #-}
diff --git a/Numeric/AD/Internal/Forward.hs b/Numeric/AD/Internal/Forward.hs
--- a/Numeric/AD/Internal/Forward.hs
+++ b/Numeric/AD/Internal/Forward.hs
@@ -20,9 +20,9 @@
     , unbundle
     , apply
     , bind
-    , bind2
+    , bind'
     , bindWith
-    , bindWith2
+    , bindWith'
     , transposeWith
     ) where
 
@@ -96,8 +96,8 @@
         outer !i _ = (i + 1, f $ snd $ mapAccumL (inner i) 0 as)
         inner !i !j a = (j + 1, bundle a $ if i == j then 1 else 0)
 
-bind2 :: (Traversable f, Num a) => (f (AD Forward a) -> b) -> f a -> (b, f b)
-bind2 f as = dropIx $ mapAccumL outer (0 :: Int, b0) as
+bind' :: (Traversable f, Num a) => (f (AD Forward a) -> b) -> f a -> (b, f b)
+bind' f as = dropIx $ mapAccumL outer (0 :: Int, b0) as
     where
         outer (!i, _) _ = let b = f $ snd $ mapAccumL (inner i) (0 :: Int) as in ((i + 1, b), b)
         inner !i !j a = (j + 1, bundle a $ if i == j then 1 else 0)
@@ -110,8 +110,8 @@
         outer !i a = (i + 1, g a $ f $ snd $ mapAccumL (inner i) 0 as)
         inner !i !j a = (j + 1, bundle a $ if i == j then 1 else 0)
 
-bindWith2 :: (Traversable f, Num a) => (a -> b -> c) -> (f (AD Forward a) -> b) -> f a -> (b, f c)
-bindWith2 g f as = dropIx $ mapAccumL outer (0 :: Int, b0) as
+bindWith' :: (Traversable f, Num a) => (a -> b -> c) -> (f (AD Forward a) -> b) -> f a -> (b, f c)
+bindWith' g f as = dropIx $ mapAccumL outer (0 :: Int, b0) as
     where
         outer (!i, _) a = let b = f $ snd $ mapAccumL (inner i) (0 :: Int) as in ((i + 1, b), g a b)
         inner !i !j a = (j + 1, bundle a $ if i == j then 1 else 0)
diff --git a/Numeric/AD/Internal/Reverse.hs b/Numeric/AD/Internal/Reverse.hs
--- a/Numeric/AD/Internal/Reverse.hs
+++ b/Numeric/AD/Internal/Reverse.hs
@@ -24,7 +24,7 @@
     , partialArray
     , partialMap
     , derivative
-    , derivative2
+    , derivative'
     , Var(..)
     , bind
     , unbind
@@ -118,9 +118,9 @@
 derivative = sum . map snd . partials
 {-# INLINE derivative #-}
 
-derivative2 :: Num a => AD Reverse a -> (a, a)
-derivative2 r = (primal r, derivative r)
-{-# INLINE derivative2 #-}
+derivative' :: Num a => AD Reverse a -> (a, a)
+derivative' r = (primal r, derivative r)
+{-# INLINE derivative' #-}
 
 -- | back propagate sensitivities along a tape.
 backPropagate :: Num a => (Vertex -> (Tape a Int, Int, [Int])) -> STArray s Int a -> Vertex -> ST s ()
@@ -204,10 +204,10 @@
 unbind xs ys = fmap (\v -> ys ! varId v) xs
 
 unbindWith :: (Functor f, Var v, Num a) => (a -> b -> c) -> f (v a) -> Array Int b -> f c
-unbindWith f xs ys = fmap (\v -> f (primal v) (ys ! varId v)) xs 
+unbindWith f xs ys = fmap (\v -> f (primal v) (ys ! varId v)) xs
 
 unbindMap :: (Functor f, Var v, Num a) => f (v a) -> IntMap a -> f a
 unbindMap xs ys = fmap (\v -> findWithDefault 0 (varId v) ys) xs
 
 unbindMapWithDefault :: (Functor f, Var v, Num a) => b -> (a -> b -> c) -> f (v a) -> IntMap b -> f c
-unbindMapWithDefault z f xs ys = fmap (\v -> f (primal v) $ findWithDefault z (varId v) ys) xs 
+unbindMapWithDefault z f xs ys = fmap (\v -> f (primal v) $ findWithDefault z (varId v) ys) xs
diff --git a/Numeric/AD/Internal/Tower.hs b/Numeric/AD/Internal/Tower.hs
--- a/Numeric/AD/Internal/Tower.hs
+++ b/Numeric/AD/Internal/Tower.hs
@@ -14,7 +14,7 @@
     ( Tower(..)
     , zeroPad
     , d
-    , d2
+    , d'
     , tangents
     , bundle
     , apply
@@ -39,11 +39,11 @@
 d _ = 0
 {-# INLINE d #-}
 
-d2 :: Num a => [a] -> (a, a)
-d2 (a:da:_) = (a, da)
-d2 (a:_)    = (a, 0)
-d2 _        = (0, 0)
-{-# INLINE d2 #-}
+d' :: Num a => [a] -> (a, a)
+d' (a:da:_) = (a, da)
+d' (a:_)    = (a, 0)
+d' _        = (0, 0)
+{-# INLINE d' #-}
 
 tangents :: Tower a -> Tower a
 tangents (Tower []) = Tower []
diff --git a/Numeric/AD/Newton.hs b/Numeric/AD/Newton.hs
--- a/Numeric/AD/Newton.hs
+++ b/Numeric/AD/Newton.hs
@@ -29,8 +29,8 @@
 import Numeric.AD.Internal
 import Data.Foldable (all)
 import Data.Traversable (Traversable)
-import Numeric.AD.Forward (diff, diff2)
-import Numeric.AD.Reverse (gradWith2)
+import Numeric.AD.Forward (diff, diff')
+import Numeric.AD.Reverse (gradWith')
 
 -- | The 'findZero' function finds a zero of a scalar function using
 -- Newton's method; its output is a stream of increasingly accurate
@@ -44,7 +44,7 @@
 --  > take 10 $ findZero ((+1).(^2)) (1 :+ 1)  -- converge to (0 :+ 1)@
 --
 findZero :: Fractional a => (forall s. Mode s => AD s a -> AD s a) -> a -> [a]
-findZero f x0 = iterate (\x -> let (y,y') = diff2 f x in x - y/y') x0
+findZero f x0 = iterate (\x -> let (y,y') = diff' f x in x - y/y') x0
 {-# INLINE findZero #-}
 
 -- | The 'inverseNewton' function inverts a scalar function using
@@ -83,7 +83,7 @@
 gradientDescent :: (Traversable f, Fractional a, Ord a) => (forall s. Mode s => f (AD s a) -> AD s a) -> f a -> [f a]
 gradientDescent f x0 = go x0 fx0 xgx0 0.1 (0 :: Int)
     where
-        (fx0, xgx0) = gradWith2 (,) f x0
+        (fx0, xgx0) = gradWith' (,) f x0
         go x fx xgx !eta !i
             | eta == 0     = [] -- step size is 0
             | fx1 > fx     = go x fx xgx (eta/2) 0 -- we stepped too far
@@ -94,6 +94,6 @@
             where
                 zeroGrad = all (\(_,g) -> g == 0)
                 x1 = fmap (\(xi,gxi) -> xi - eta * gxi) xgx
-                (fx1, xgx1) = gradWith2 (,) f x1
-                
+                (fx1, xgx1) = gradWith' (,) f x1
+
 {-# INLINE gradientDescent #-}
diff --git a/Numeric/AD/Reverse.hs b/Numeric/AD/Reverse.hs
--- a/Numeric/AD/Reverse.hs
+++ b/Numeric/AD/Reverse.hs
@@ -21,30 +21,33 @@
     (
     -- * Gradient
       grad
-    , grad2
+    , grad'
     , gradWith
-    , gradWith2
+    , gradWith'
     -- * Jacobian
     , jacobian
-    , jacobian2
+    , jacobian'
     , jacobianWith
-    , jacobianWith2
+    , jacobianWith'
     -- * Derivatives
-    , diffUU
-    , diff2UU
-    , diffFU
-    , diff2FU
-    , diffUF
-    , diff2UF
-    -- * Synonyms
     , diff
-    , diff2
+    , diff'
+    , diffF
+    , diffF'
+    -- * Monadic Combinators
+    , diffM
+    , diffM'
+    , gradM
+    , gradM'
+    , gradWithM
+    , gradWithM'
     -- * Exposed Types
     , AD(..)
     , Mode(..)
     ) where
 
-import Control.Applicative ((<$>))
+import Control.Monad (liftM)
+import Control.Applicative (WrappedMonad(..),(<$>))
 import Data.Traversable (Traversable)
 
 import Numeric.AD.Classes
@@ -57,32 +60,32 @@
     where (vs,bds) = bind as
 {-# INLINE grad #-}
 
--- | The 'grad2' function calculates the result and gradient of a non-scalar-to-scalar function with 'Reverse' AD in a single pass.
-grad2 :: (Traversable f, Num a) => (forall s. Mode s => f (AD s a) -> AD s a) -> f a -> (a, f a)
-grad2 f as = (primal r, unbind vs $ partialArray bds r)
+-- | The 'grad'' function calculates the result and gradient of a non-scalar-to-scalar function with 'Reverse' AD in a single pass.
+grad' :: (Traversable f, Num a) => (forall s. Mode s => f (AD s a) -> AD s a) -> f a -> (a, f a)
+grad' f as = (primal r, unbind vs $ partialArray bds r)
     where (vs, bds) = bind as
           r = f vs
-{-# INLINE grad2 #-}
+{-# INLINE grad' #-}
 
 -- | @'grad' g f@ function calculates the gradient of a non-scalar-to-scalar function @f@ with reverse-mode AD in a single pass.
 -- The gradient is combined element-wise with the argument using the function @g@.
 --
--- > grad == gradWith (\_ dx -> dx) 
+-- > grad == gradWith (\_ dx -> dx)
 -- > id == gradWith const
 gradWith :: (Traversable f, Num a) => (a -> a -> b) -> (forall s. Mode s => f (AD s a) -> AD s a) -> f a -> f b
 gradWith g f as = unbindWith g vs (partialArray bds $ f vs)
     where (vs,bds) = bind as
 {-# INLINE gradWith #-}
 
--- | @'grad2' g f@ calculates the result and gradient of a non-scalar-to-scalar function @f@ with 'Reverse' AD in a single pass
+-- | @'grad'' g f@ calculates the result and gradient of a non-scalar-to-scalar function @f@ with 'Reverse' AD in a single pass
 -- the gradient is combined element-wise with the argument using the function @g@.
--- 
--- > grad2 == gradWith2 (\_ dx -> dx)
-gradWith2 :: (Traversable f, Num a) => (a -> a -> b) -> (forall s. Mode s => f (AD s a) -> AD s a) -> f a -> (a, f b)
-gradWith2 g f as = (primal r, unbindWith g vs $ partialArray bds r)
+--
+-- > grad' == gradWith' (\_ dx -> dx)
+gradWith' :: (Traversable f, Num a) => (a -> a -> b) -> (forall s. Mode s => f (AD s a) -> AD s a) -> f a -> (a, f b)
+gradWith' g f as = (primal r, unbindWith g vs $ partialArray bds r)
     where (vs, bds) = bind as
           r = f vs
-{-# INLINE gradWith2 #-}
+{-# INLINE gradWith' #-}
 
 -- | The 'jacobian' function calculates the jacobian of a non-scalar-to-non-scalar function with reverse AD lazily in @m@ passes for @m@ outputs.
 jacobian :: (Traversable f, Functor g, Num a) => (forall s. Mode s => f (AD s a) -> g (AD s a)) -> f a -> g (f a)
@@ -90,18 +93,18 @@
     (vs, bds) = bind as
 {-# INLINE jacobian #-}
 
--- | The 'jacobian2' function calculates both the result and the Jacobian of a nonscalar-to-nonscalar function, using @m@ invocations of reverse AD,
+-- | The 'jacobian'' function calculates both the result and the Jacobian of a nonscalar-to-nonscalar function, using @m@ invocations of reverse AD,
 -- where @m@ is the output dimensionality. Applying @fmap snd@ to the result will recover the result of 'jacobian'
-jacobian2 :: (Traversable f, Functor g, Num a) => (forall s. Mode s => f (AD s a) -> g (AD s a)) -> f a -> g (a, f a)
-jacobian2 f as = row <$> f vs where
+jacobian' :: (Traversable f, Functor g, Num a) => (forall s. Mode s => f (AD s a) -> g (AD s a)) -> f a -> g (a, f a)
+jacobian' f as = row <$> f vs where
     (vs, bds) = bind as
     row a = (primal a, unbind vs (partialArray bds a))
-{-# INLINE jacobian2 #-}
+{-# INLINE jacobian' #-}
 
 -- | 'jacobianWith g f' calculates the jacobian of a non-scalar-to-non-scalar function @f@ with reverse AD lazily in @m@ passes for @m@ outputs.
 --
 -- Instead of returning the Jacobian matrix, the elements of the matrix are combined with the input using the @g@.
--- 
+--
 -- > jacobian == jacobianWith (\_ dx -> dx)
 -- > jacobianWith const == (\f x -> const x <$> f x)
 --
@@ -110,55 +113,58 @@
     (vs, bds) = bind as
 {-# INLINE jacobianWith #-}
 
--- | 'jacobianWith2 g f' calculates both the result and the Jacobian of a nonscalar-to-nonscalar function @f@, using @m@ invocations of reverse AD,
+-- | 'jacobianWith' g f' calculates both the result and the Jacobian of a nonscalar-to-nonscalar function @f@, using @m@ invocations of reverse AD,
 -- where @m@ is the output dimensionality. Applying @fmap snd@ to the result will recover the result of 'jacobianWith'
--- 
+--
 -- Instead of returning the Jacobian matrix, the elements of the matrix are combined with the input using the @g@.
 --
--- > jacobian2 == jacobianWith2 (\_ dx -> dx)
+-- > jacobian' == jacobianWith' (\_ dx -> dx)
 --
-jacobianWith2 :: (Traversable f, Functor g, Num a) => (a -> a -> b) -> (forall s. Mode s => f (AD s a) -> g (AD s a)) -> f a -> g (a, f b)
-jacobianWith2 g f as = row <$> f vs where
+jacobianWith' :: (Traversable f, Functor g, Num a) => (a -> a -> b) -> (forall s. Mode s => f (AD s a) -> g (AD s a)) -> f a -> g (a, f b)
+jacobianWith' g f as = row <$> f vs where
     (vs, bds) = bind as
     row a = (primal a, unbindWith g vs (partialArray bds a))
-{-# INLINE jacobianWith2 #-}
-
-diffUU :: Num a => (forall s. Mode s => AD s a -> AD s a) -> a -> a
-diffUU f a = derivative $ f (var a 0)
-{-# INLINE diffUU #-}
+{-# INLINE jacobianWith' #-}
 
-diffUF :: (Functor f, Num a) => (forall s. Mode s => AD s a -> f (AD s a)) -> a -> f a
-diffUF f a = derivative <$> f (var a 0)
-{-# INLINE diffUF #-}
+diff :: Num a => (forall s. Mode s => AD s a -> AD s a) -> a -> a
+diff f a = derivative $ f (var a 0)
+{-# INLINE diff #-}
 
--- | The 'diff2UU' function calculates the value and derivative, as a
+-- | The 'd'' function calculates the value and derivative, as a
 -- pair, of a scalar-to-scalar function.
-diff2UU :: Num a => (forall s. Mode s => AD s a -> AD s a) -> a -> (a, a)
-diff2UU f a = derivative2 $ f (var a 0)
-{-# INLINE diff2UU #-}
+diff' :: Num a => (forall s. Mode s => AD s a -> AD s a) -> a -> (a, a)
+diff' f a = derivative' $ f (var a 0)
+{-# INLINE diff' #-}
 
-diff2UF :: (Functor f, Num a) => (forall s. Mode s => AD s a -> f (AD s a)) -> a -> f (a, a)
-diff2UF f a = derivative2 <$> f (var a 0)
-{-# INLINE diff2UF #-}
+diffF :: (Functor f, Num a) => (forall s. Mode s => AD s a -> f (AD s a)) -> a -> f a
+diffF f a = derivative <$> f (var a 0)
+{-# INLINE diffF #-}
 
-diffFU :: (Traversable f, Num a) => (forall s. Mode s => f (AD s a) -> AD s a) -> f a -> f a
-diffFU f as = unbind vs $ partialArray bds (f vs)
-    where (vs, bds) = bind as
-{-# INLINE diffFU #-}
+diffF' :: (Functor f, Num a) => (forall s. Mode s => AD s a -> f (AD s a)) -> a -> f (a, a)
+diffF' f a = derivative' <$> f (var a 0)
+{-# INLINE diffF' #-}
 
-diff2FU :: (Traversable f, Num a) => (forall s. Mode s => f (AD s a) -> AD s a) -> f a -> (a, f a)
-diff2FU f as = (primal result, unbind vs $ partialArray bds result)
-    where (vs, bds) = bind as
-          result = f vs
-{-# INLINE diff2FU #-}
+-- * Monadic Combinators
 
--- | The 'diff' function is a synonym for 'diffUU'.
-diff :: Num a => (forall s. Mode s => AD s a -> AD s a) -> a -> a
-diff = diffUU
-{-# INLINE diff #-}
+diffM :: (Monad m, Num a) => (forall s. Mode s => AD s a -> m (AD s a)) -> a -> m a
+diffM f a = liftM derivative $ f (var a 0)
+{-# INLINE diffM #-}
 
--- | The 'diff2' function is a synonym for 'diff2UU'.
-diff2 :: Num a => (forall s. Mode s => AD s a -> AD s a) -> a -> (a, a)
-diff2 = diff2UU
-{-# INLINE diff2 #-}
+diffM' :: (Monad m, Num a) => (forall s. Mode s => AD s a -> m (AD s a)) -> a -> m (a, a)
+diffM' f a = liftM derivative' $ f (var a 0)
+{-# INLINE diffM' #-}
+
+gradM :: (Traversable f, Monad m, Num a) => (forall s. Mode s => f (AD s a) -> m (AD s a)) -> f a -> m (f a)
+gradM f = unwrapMonad . jacobian (WrapMonad . f)
+{-# INLINE gradM #-}
+
+gradM' :: (Traversable f, Monad m, Num a) => (forall s. Mode s => f (AD s a) -> m (AD s a)) -> f a -> m (a, f a)
+gradM' f = unwrapMonad . jacobian' (WrapMonad . f)
+{-# INLINE gradM' #-}
+
+gradWithM :: (Traversable f, Monad m, Num a) => (a -> a -> b) -> (forall s. Mode s => f (AD s a) -> m (AD s a)) -> f a -> m (f b)
+gradWithM g f = unwrapMonad . jacobianWith g (WrapMonad . f)
+
+gradWithM' :: (Traversable f, Monad m, Num a) => (a -> a -> b) -> (forall s. Mode s => f (AD s a) -> m (AD s a)) -> f a -> m (a, f b)
+gradWithM' g f = unwrapMonad . jacobianWith' g (WrapMonad . f)
 
diff --git a/Numeric/AD/Tower.hs b/Numeric/AD/Tower.hs
--- a/Numeric/AD/Tower.hs
+++ b/Numeric/AD/Tower.hs
@@ -15,54 +15,56 @@
 module Numeric.AD.Tower
     (
     -- * Taylor Series
-      taylor, taylor0
-    , maclaurin, maclaurin0
+      taylor
+    , taylor0
+    -- * Maclaurin Series
+    , maclaurin
+    , maclaurin0
     -- * Derivatives
-    , diffUU
-    , diff2UU
-    , diffsUU
-    , diffs0UU
-    , diffsUF
-    , diffs0UF
-    -- * Synonyms
-    , diffs, diffs0
-    , diff, diff2
+    , diff
+    , diff'
+    , diffs
+    , diffs0
+    , diffsF
+    , diffs0F
+    -- * Monadic Combinators
+    , diffsM
+    , diffs0M
     -- * Exposed Types
     , Mode(..)
     , AD(..)
     ) where
 
--- TODO: argminNaiveGradient
-
+import Control.Monad (liftM)
 import Control.Applicative ((<$>))
 import Numeric.AD.Classes
 import Numeric.AD.Internal
 import Numeric.AD.Internal.Tower
 
-diffsUU :: Num a => (forall s. Mode s => AD s a -> AD s a) -> a -> [a]
-diffsUU f a = getADTower $ apply f a
-{-# INLINE diffsUU #-}
-
-diffs0UU :: Num a => (forall s. Mode s => AD s a -> AD s a) -> a -> [a]
-diffs0UU f a = zeroPad (diffsUU f a)
-{-# INLINE diffs0UU #-}
-
-diffs0UF :: (Functor f, Num a) => (forall s. Mode s => AD s a -> f (AD s a)) -> a -> f [a]
-diffs0UF f a = (zeroPad . getADTower) <$> apply f a
-{-# INLINE diffs0UF #-}
-
-diffsUF :: (Functor f, Num a) => (forall s. Mode s => AD s a -> f (AD s a)) -> a -> f [a]
-diffsUF f a = getADTower <$> apply f a
-{-# INLINE diffsUF #-}
-
 diffs :: Num a => (forall s. Mode s => AD s a -> AD s a) -> a -> [a]
-diffs = diffsUU
+diffs f a = getADTower $ apply f a
 {-# INLINE diffs #-}
 
 diffs0 :: Num a => (forall s. Mode s => AD s a -> AD s a) -> a -> [a]
-diffs0 = diffs0UU
+diffs0 f a = zeroPad (diffs f a)
 {-# INLINE diffs0 #-}
 
+diffsF :: (Functor f, Num a) => (forall s. Mode s => AD s a -> f (AD s a)) -> a -> f [a]
+diffsF f a = getADTower <$> apply f a
+{-# INLINE diffsF #-}
+
+diffs0F :: (Functor f, Num a) => (forall s. Mode s => AD s a -> f (AD s a)) -> a -> f [a]
+diffs0F f a = (zeroPad . getADTower) <$> apply f a
+{-# INLINE diffs0F #-}
+
+diffsM :: (Monad m, Num a) => (forall s. Mode s => AD s a -> m (AD s a)) -> a -> m [a]
+diffsM f a = getADTower `liftM` apply f a
+{-# INLINE diffsM #-}
+
+diffs0M :: (Monad m, Num a) => (forall s. Mode s => AD s a -> m (AD s a)) -> a -> m [a]
+diffs0M f a = (zeroPad . getADTower) `liftM` apply f a
+{-# INLINE diffs0M #-}
+
 taylor :: Fractional a => (forall s. Mode s => AD s a -> AD s a) -> a -> a -> [a]
 taylor f x dx = go 1 1 (diffs f x)
     where
@@ -81,18 +83,11 @@
 maclaurin0 f = taylor0 f 0
 {-# INLINE maclaurin0 #-}
 
-diffUU :: Num a => (forall s. Mode s => AD s a -> AD s a) -> a -> a
-diffUU f a = d $ diffs f a
-{-# INLINE diffUU #-}
-
-diff2UU :: Num a => (forall s. Mode s => AD s a -> AD s a) -> a -> (a, a)
-diff2UU f a = d2 $ diffs f a
-{-# INLINE diff2UU #-}
-
 diff :: Num a => (forall s. Mode s => AD s a -> AD s a) -> a -> a
-diff = diffUU
+diff f a = d $ diffs f a
 {-# INLINE diff #-}
 
-diff2 :: Num a => (forall s. Mode s => AD s a -> AD s a) -> a -> (a, a)
-diff2 = diff2UU
-{-# INLINE diff2 #-}
+diff' :: Num a => (forall s. Mode s => AD s a -> AD s a) -> a -> (a, a)
+diff' f a = d' $ diffs f a
+{-# INLINE diff' #-}
+
diff --git a/ad.cabal b/ad.cabal
--- a/ad.cabal
+++ b/ad.cabal
@@ -1,5 +1,5 @@
 Name:         ad
-Version:      0.15
+Version:      0.17
 License:      BSD3
 License-File: LICENSE
 Copyright:    Edward Kmett 2010
