diff --git a/Numeric/AD.hs b/Numeric/AD.hs
--- a/Numeric/AD.hs
+++ b/Numeric/AD.hs
@@ -6,15 +6,15 @@
 -- License     :  BSD3
 -- Maintainer  :  ekmett@gmail.com
 -- Stability   :  experimental
--- Portability :  GHC only 
+-- Portability :  GHC only
 --
 -- Mixed-Mode Automatic Differentiation.
--- 
+--
 -- Each combinator exported from this module chooses an appropriate AD mode.
 -----------------------------------------------------------------------------
 
-module Numeric.AD 
-    ( 
+module Numeric.AD
+    (
     -- * Gradients
       grad, grad2
 
@@ -58,9 +58,9 @@
 import Data.Foldable (Foldable, foldr')
 import Control.Applicative
 import Numeric.AD.Classes  (Mode(..))
-import Numeric.AD.Internal (AD(..), probe, unprobe)
+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.Tower    (diffsUU, diffs0UU , diffsUF, diffs0UF , diffs, diffs0, taylor, taylor0)
 import Numeric.AD.Reverse  (diffFU, diff2FU, grad, grad2)
 
 import qualified Numeric.AD.Forward as Forward
@@ -77,9 +77,9 @@
                | n > m     = Reverse.jacobian2 f bs
                | otherwise = Forward.jacobian2 f bs
     where
-        as = f (probe <$> bs)
+        as = f (probed bs)
         n = size bs
         m = size as
         size :: Foldable f => f a -> Int
-        size = foldr' (\_ b -> 1 + b) 0 
+        size = foldr' (\_ b -> 1 + b) 0
 {-# INLINE jacobian2 #-}
diff --git a/Numeric/AD/Classes.hs b/Numeric/AD/Classes.hs
--- a/Numeric/AD/Classes.hs
+++ b/Numeric/AD/Classes.hs
@@ -6,14 +6,14 @@
 -- License     :  BSD3
 -- Maintainer  :  ekmett@gmail.com
 -- Stability   :  experimental
--- Portability :  GHC only 
+-- Portability :  GHC only
 --
 -----------------------------------------------------------------------------
 
 module Numeric.AD.Classes
-    ( 
+    (
     -- * AD modes
-      Mode(..) 
+      Mode(..)
     , one
     -- * Automatically Deriving AD
     , Jacobian(..)
@@ -30,7 +30,7 @@
 
 infixl 8 **!
 infixl 7 *!, /!, ^*, *^, ^/
-infixl 6 +!, -!, <+> 
+infixl 6 +!, -!, <+>
 infix 4 ==!
 
 -- | Higher-order versions of the stock numerical methods.
@@ -56,20 +56,20 @@
 -- class (Show1 t, Eq t) => Num1 t where
     fromInteger1 :: Num a => Integer -> t a
     (+!),(-!),(*!) :: Num a => t a -> t a -> t a
-    negate1, abs1, signum1 :: Num a => t a -> t a 
+    negate1, abs1, signum1 :: Num a => t a -> t a
 
 -- class Num1 t => Fractional1 t where
     (/!) :: Fractional a => t a -> t a -> t a
     recip1 :: Fractional a => t a -> t a
-    fromRational1 :: Fractional a => Rational -> t a 
+    fromRational1 :: Fractional a => Rational -> t a
 
--- class (Num1 t, Ord1 t) => Real1 t 
+-- class (Num1 t, Ord1 t) => Real1 t
     toRational1 :: Real a => t a -> Rational -- unsafe
 
--- class Fractional1 t => Floating1 t 
-    pi1 :: Floating a => t a 
+-- class Fractional1 t => Floating1 t
+    pi1 :: Floating a => t a
     exp1, log1, sqrt1 :: Floating a => t a -> t a
-    (**!), logBase1 :: Floating a => t a -> t a -> t a 
+    (**!), logBase1 :: Floating a => t a -> t a -> t a
     sin1, cos1, tan1, asin1, acos1, atan1 :: Floating a => t a -> t a
     sinh1, cosh1, tanh1, asinh1, acosh1, atanh1 :: Floating a => t a -> t a
 
@@ -86,7 +86,7 @@
     encodeFloat1  :: RealFloat a => Integer -> Int -> t a
     exponent1     :: RealFloat a => t a -> Int
     significand1  :: RealFloat a => t a -> t a
-    scaleFloat1   :: RealFloat a => Int -> t a -> t a 
+    scaleFloat1   :: RealFloat a => Int -> t a -> t a
     isNaN1, isInfinite1, isDenormalized1, isNegativeZero1, isIEEE1 :: RealFloat a => t a -> Bool
     atan21 :: RealFloat a => t a -> t a -> t a
 
@@ -100,13 +100,13 @@
     enumFromThenTo1 :: (Num a, Enum a) => t a -> t a -> t a -> [t a]
 
 -- class Bounded1 t where
-    minBound1 :: (Num a, Bounded a) => t a 
+    minBound1 :: (Num a, Bounded a) => t a
     maxBound1 :: (Num a, Bounded a) => t a
 
 class Lifted t => Mode t where
 
     -- | Embed a constant
-    lift  :: Num a => a -> t a 
+    lift  :: Num a => a -> t a
 
     -- | Vector sum
     (<+>) :: Num a => t a -> t a -> t a
@@ -118,7 +118,7 @@
     (^*) :: Num a => t a -> a -> t a
 
     -- | Scalar division
-    (^/) :: Fractional a => t a -> a -> t a 
+    (^/) :: Fractional a => t a -> a -> t a
 
     -- | > 'zero' = 'lift' 0
     zero :: Num a => t a
@@ -139,9 +139,9 @@
 negOne = lift (-1)
 {-# INLINE negOne #-}
 
--- | 'Primal' is used by 'deriveMode' but is not exposed 
+-- | 'Primal' is used by 'deriveMode' but is not exposed
 -- via the 'Mode' class to prevent its abuse by end users
--- via the AD data type. 
+-- via the AD data type.
 --
 -- It provides direct access to the result, stripped of its derivative information,
 -- but this is unsafe in general as (lift . primal) would discard derivative
@@ -153,7 +153,7 @@
 
 -- | 'Jacobian' is used by 'deriveMode' but is not exposed
 -- via 'Mode' to prevent its abuse by end users
--- via the 'AD' data type. 
+-- via the 'AD' data type.
 class (Mode t, Mode (D t)) => Jacobian t where
     type D t :: * -> *
 
@@ -168,7 +168,7 @@
 withPrimal :: (Jacobian t, Num a) => t a -> a -> t a
 withPrimal t a = unary (const a) one t
 
-fromBy :: (Jacobian t, Num a) => t a -> t a -> Int -> a -> t a 
+fromBy :: (Jacobian t, Num a) => t a -> t a -> Int -> a -> t a
 fromBy a delta n x = binary (\_ _ -> x) one (fromIntegral1 n) a delta
 
 fromIntegral1 :: (Integral n, Lifted t, Num a) => n -> t a
@@ -176,7 +176,7 @@
 {-# INLINE fromIntegral1 #-}
 
 square1 :: (Lifted t, Num a) => t a -> t a
-square1 x = x *! x 
+square1 x = x *! x
 {-# INLINE square1 #-}
 
 on :: (a -> a -> c) -> (b -> a) -> b -> b -> c
@@ -193,16 +193,16 @@
 
 -- | @'deriveLifted' t@ provides
 --
--- > instance Lifted $t 
+-- > instance Lifted $t
 --
 -- given supplied instances for
 --
--- > instance Lifted $t => Primal $t where ... 
+-- > instance Lifted $t => Primal $t where ...
 -- > instance Lifted $t => Jacobian $t where ...
--- 
+--
 -- The seemingly redundant @'Lifted' $t@ constraints are caused by Template Haskell staging restrictions.
 deriveLifted :: Q Type -> Q [Dec]
-deriveLifted _t = [d| 
+deriveLifted _t = [d|
     instance Lifted $_t where
         (==!)         = (==) `on` primal
         compare1      = compare `on` primal
@@ -219,16 +219,16 @@
         fromRational1 = lift . fromRational
         (/!)          = lift2 (/) $ \x y -> (recip1 y, x)
         recip1        = lift1 recip (negate1 . square1)
-    
+
         pi1       = lift pi
         exp1      = lift1_ exp const
         log1      = lift1 log recip1
         logBase1 x y = log1 y /! log1 x
         sqrt1     = lift1_ sqrt (\z _ -> recip1 (lift 2 *! z))
-        (**!)     = lift2_ (**) (\z x y -> (y *! z /! x, z *! log1 x)) -- error at 0 ** n 
+        (**!)     = lift2_ (**) (\z x y -> (y *! z /! x, z *! log1 x)) -- error at 0 ** n
         sin1      = lift1 sin cos1
         cos1      = lift1 cos $ \x -> negate1 (sin1 x)
-        tan1 x    = sin1 x /! cos1 x 
+        tan1 x    = sin1 x /! cos1 x
         asin1     = lift1 asin $ \x -> recip1 (sqrt1 (one -! square1 x))
         acos1     = lift1 acos $ \x -> negate1 (recip1 (sqrt1 (one -! square1 x)))
         atan1     = lift1 atan $ \x -> recip1 (one +! square1 x)
@@ -238,16 +238,16 @@
         asinh1    = lift1 asinh $ \x -> recip1 (sqrt1 (one +! square1 x))
         acosh1    = lift1 acosh $ \x -> recip1 (sqrt1 (square1 x -! one))
         atanh1    = lift1 atanh $ \x -> recip1 (one -! square1 x)
-    
+
         succ1                 = lift1 succ (const one)
         pred1                 = lift1 pred (const one)
         toEnum1               = lift . toEnum
-        fromEnum1             = discrete1 fromEnum 
+        fromEnum1             = discrete1 fromEnum
         enumFrom1 a           = withPrimal a <$> discrete1 enumFrom a
         enumFromTo1 a b       = withPrimal a <$> discrete2 enumFromTo a b
         enumFromThen1 a b     = zipWith (fromBy a delta) [0..] $ discrete2 enumFromThen a b where delta = b -! a
         enumFromThenTo1 a b c = zipWith (fromBy a delta) [0..] $ discrete3 enumFromThenTo a b c where delta = b -! a
-    
+
         toRational1      = discrete1 toRational
         floatRadix1      = discrete1 floatRadix
         floatDigits1     = discrete1 floatDigits
@@ -260,20 +260,20 @@
         isNegativeZero1  = discrete1 isNegativeZero
         isIEEE1          = discrete1 isIEEE
         exponent1 = exponent . primal
-        scaleFloat1 n = unary (scaleFloat n) (scaleFloat1 n one) 
+        scaleFloat1 n = unary (scaleFloat n) (scaleFloat1 n one)
         significand1 x =  unary significand (scaleFloat1 (- floatDigits1 x) one) x
         atan21 = lift2 atan2 $ \vx vy -> let r = recip1 (square1 vx +! square1 vy) in (vy *! r, negate1 vx *! r)
-        properFraction1 a = (w, a `withPrimal` pb) where 
-             pa = primal a 
+        properFraction1 a = (w, a `withPrimal` pb) where
+             pa = primal a
              (w, pb) = properFraction pa
         truncate1 = discrete1 truncate
         round1    = discrete1 round
         ceiling1  = discrete1 ceiling
-        floor1    = discrete1 floor 
+        floor1    = discrete1 floor
     |]
-    
+
 varA :: Q Type
-varA = varT (mkName "a") 
+varA = varT (mkName "a")
 
 -- | Find all the members defined in the 'Lifted' data type
 liftedMembers :: Q [String]
@@ -308,13 +308,13 @@
     instanceD (cxt (f [classP ''Lifted [t], classP n [varA]]))
               (conT n `appT` (t' `appT` varA))
               (concatMap lower1 ds)
-    where 
+    where
         lower1 :: Dec -> [Q Dec]
         lower1 (SigD n' _) | p n'' = [valD (varP n') (normalB (varE n'')) []] where n'' = primed n'
         lower1 _          = []
 
         primed n' = mkName $ base ++ [prime]
-            where 
+            where
                 base = nameBase n'
                 h = head base
                 prime | isSymbol h || h `elem` "/*-<>" = '!'
diff --git a/Numeric/AD/Directed.hs b/Numeric/AD/Directed.hs
--- a/Numeric/AD/Directed.hs
+++ b/Numeric/AD/Directed.hs
@@ -6,14 +6,14 @@
 -- License     :  BSD3
 -- Maintainer  :  ekmett@gmail.com
 -- Stability   :  experimental
--- Portability :  GHC only 
+-- Portability :  GHC only
 --
 -- Allows the choice of AD 'Mode' to be specified at the term level for
 -- benchmarking or more complicated usage patterns.
 -----------------------------------------------------------------------------
 
 module Numeric.AD.Directed
-    ( 
+    (
     -- * Derivatives
       diffUU
     , diff2UU
@@ -44,11 +44,11 @@
 
 -- TODO: use a data types a la carte approach, so we can expose more methods here
 -- rather than just the intersection of all of the functionality
-data Direction 
-    = Forward 
-    | Reverse 
-    | Tower 
-    | Mixed 
+data Direction
+    = Forward
+    | Reverse
+    | Tower
+    | 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
@@ -58,7 +58,7 @@
 diffUU Mixed = F.diffUU
 {-# INLINE diffUU #-}
 
-diff2UU :: Num a => Direction -> (forall s. Mode s => AD s a -> AD s a) -> a -> (a, a) 
+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
@@ -69,7 +69,7 @@
 diff = diffUU
 {-# INLINE diff #-}
 
-diff2 :: Num a => Direction -> (forall s. Mode s => AD s a -> AD s a) -> a -> (a, a) 
+diff2 :: Num a => Direction -> (forall s. Mode s => AD s a -> AD s a) -> a -> (a, a)
 diff2 = diff2UU
 {-# INLINE diff2 #-}
 
diff --git a/Numeric/AD/Forward.hs b/Numeric/AD/Forward.hs
--- a/Numeric/AD/Forward.hs
+++ b/Numeric/AD/Forward.hs
@@ -6,14 +6,14 @@
 -- License     :  BSD3
 -- Maintainer  :  ekmett@gmail.com
 -- Stability   :  experimental
--- Portability :  GHC only 
+-- Portability :  GHC only
 --
 -- Forward mode automatic differentiation
 --
 -----------------------------------------------------------------------------
 
 module Numeric.AD.Forward
-    ( 
+    (
     -- * Gradient
       grad
     , grad2
@@ -46,7 +46,7 @@
 {-# 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 :: Num a => (forall s. Mode s => AD s a -> AD s a) -> a -> (a, a)
 diff2 = diff2UU
 {-# INLINE diff2 #-}
 
@@ -56,7 +56,7 @@
 {-# INLINE diffUU #-}
 
 -- | 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 :: Num a => (forall s. Mode s => AD s a -> AD s a) -> a -> (a, a)
 diff2UU f a = unbundle $ apply f a
 {-# INLINE diff2UU #-}
 
@@ -66,7 +66,7 @@
 {-# INLINE diffUF #-}
 
 -- | 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 :: (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 #-}
 
@@ -78,15 +78,15 @@
 
 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 
+    where
+        (p, t) = bind2 (fmap tangent . f) as
 {-# INLINE jacobian #-}
 
 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
-    where 
-        (p, t) = bind2 f as 
-        row x as' = (primal x, tangent <$> as') 
+    where
+        (p, t) = bind2 f as
+        row x as' = (primal x, tangent <$> as')
 {-# INLINE jacobian2 #-}
 
 grad :: (Traversable f, Num a) => (forall s. Mode s => f (AD s a) -> AD s a) -> f a -> f a
@@ -95,6 +95,6 @@
 
 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)
-    where 
+    where
         (b, bs) = bind2 f as
 {-# INLINE grad2 #-}
diff --git a/Numeric/AD/Internal.hs b/Numeric/AD/Internal.hs
--- a/Numeric/AD/Internal.hs
+++ b/Numeric/AD/Internal.hs
@@ -1,4 +1,4 @@
-{-# LANGUAGE GeneralizedNewtypeDeriving, TemplateHaskell, FlexibleContexts, FlexibleInstances #-}
+{-# LANGUAGE GeneralizedNewtypeDeriving, TemplateHaskell, FlexibleContexts, FlexibleInstances, MultiParamTypeClasses #-}
 -----------------------------------------------------------------------------
 -- |
 -- Module      :  Numeric.AD.Internal
@@ -6,7 +6,7 @@
 -- License     :  BSD3
 -- Maintainer  :  ekmett@gmail.com
 -- Stability   :  experimental
--- Portability :  GHC only 
+-- Portability :  GHC only
 --
 -----------------------------------------------------------------------------
 module Numeric.AD.Internal
@@ -15,6 +15,8 @@
     , Id(..)
     , probe
     , unprobe
+    , probed
+    , unprobed
     ) where
 
 import Control.Applicative
@@ -24,19 +26,27 @@
 import Data.Traversable (Traversable, mapAccumL)
 import Data.Foldable (Foldable, toList)
 
-zipWithT :: (Foldable f, Traversable g) => (a -> b -> c) -> f a -> g b -> g c 
+zipWithT :: (Foldable f, Traversable g) => (a -> b -> c) -> f a -> g b -> g c
 zipWithT f as = snd . mapAccumL (\(a:as') b -> (as', f a b)) (toList as)
 
--- | 'AD' serves as a common wrapper for different 'Mode' instances, exposing a traditional 
--- numerical tower. Universal quantification is used to limit the actions in user code to 
+class Iso a b where
+    iso :: f a -> f b
+    osi :: f b -> f a
+
+instance Iso a a where
+    iso = id
+    osi = id
+
+-- | 'AD' serves as a common wrapper for different 'Mode' instances, exposing a traditional
+-- numerical tower. Universal quantification is used to limit the actions in user code to
 -- machinery that will return the same answers under all AD modes, allowing us to use modes
 -- interchangeably as both the type level \"brand\" and dictionary, providing a common API.
-newtype AD f a = AD { runAD :: f a } deriving (Lifted, Mode, Primal)
+newtype AD f a = AD { runAD :: f a } deriving (Iso (f a), Lifted, Mode, Primal)
 
 let f = varT (mkName "f") in deriveNumeric (conT ''AD `appT` f) f
 
 newtype Id a = Id a deriving
-    (Eq, Ord, Show, Enum, Bounded, Num, Real, Fractional, Floating, RealFrac, RealFloat, Monoid)
+    (Iso a, Eq, Ord, Show, Enum, Bounded, Num, Real, Fractional, Floating, RealFrac, RealFloat, Monoid)
 
 probe :: a -> AD Id a
 probe a = AD (Id a)
@@ -44,6 +54,18 @@
 unprobe :: AD Id a -> a
 unprobe (AD (Id a)) = a
 
+pid :: f a -> f (Id a)
+pid = iso
+
+unpid :: f (Id a) -> f a
+unpid = osi
+
+probed :: f a -> f (AD Id a)
+probed = iso . pid
+
+unprobed :: f (AD Id a) -> f a
+unprobed = unpid . osi
+
 instance Functor Id where
     fmap f (Id a) = Id (f a)
 
@@ -53,7 +75,7 @@
 
 instance Monad Id where
     return = Id
-    Id a >>= f = f a 
+    Id a >>= f = f a
 
 instance Lifted Id where
     (==!) = (==)
@@ -62,14 +84,14 @@
     fromInteger1 = fromInteger
     (+!) = (+)
     (-!) = (-)
-    (*!) = (*) 
+    (*!) = (*)
     negate1 = negate
     abs1 = abs
     signum1 = signum
     (/!) = (/)
     recip1 = recip
     fromRational1 = fromRational
-    toRational1 = toRational   
+    toRational1 = toRational
     pi1 = pi
     exp1 = exp
     log1 = log
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
@@ -6,7 +6,7 @@
 -- License     :  BSD3
 -- Maintainer  :  ekmett@gmail.com
 -- Stability   :  experimental
--- Portability :  GHC only 
+-- Portability :  GHC only
 --
 -- Unsafe and often partial combinators intended for internal usage.
 --
@@ -65,23 +65,23 @@
     type D Forward = Id
     unary f (Id dadb) (Forward b db) = Forward (f b) (dadb * db)
     lift1 f df (Forward b db) = Forward (f b) (dadb * db)
-        where 
+        where
             Id dadb = df (Id b)
     lift1_ f df (Forward b db) = Forward a da
-        where 
+        where
             a = f b
             Id da = df (Id a) (Id b) ^* db
 
     binary f (Id dadb) (Id dadc) (Forward b db) (Forward c dc) = Forward (f b c) da
-        where 
+        where
             da = dadb * db + dc * dadc
     lift2 f df (Forward b db) (Forward c dc) = Forward a da
-        where 
+        where
             a = f b c
-            (Id dadb, Id dadc) = df (Id b) (Id c) 
+            (Id dadb, Id dadc) = df (Id b) (Id c)
             da = dadb * db + dc * dadc
     lift2_ f df (Forward b db) (Forward c dc) = Forward a da
-        where 
+        where
             a = f b c
             (Id dadb, Id dadc) = df (Id a) (Id b) (Id c)
             da = dadb * db + dc * dadc
@@ -95,7 +95,7 @@
         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 
+bind2 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)
@@ -106,7 +106,7 @@
 -- traversable could be empty. So instead we use one as a 'skeleton'
 transposeWith :: (Functor f, Foldable f, Traversable g) => (b -> f a -> c) -> f (g a) -> g b -> g c
 transposeWith f as = snd . mapAccumL go xss0
-    where 
+    where
         go xss b = (tail <$> xss, f b (head <$> xss))
         xss0 = toList <$> as
 
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
@@ -6,7 +6,7 @@
 -- License     : BSD3
 -- Maintainer  : ekmett@gmail.com
 -- Stability   : experimental
--- Portability : GHC only 
+-- Portability : GHC only
 --
 -----------------------------------------------------------------------------
 
@@ -31,7 +31,7 @@
 -- Local combinators
 
 zeroPad :: Num a => [a] -> [a]
-zeroPad xs = xs ++ repeat 0 
+zeroPad xs = xs ++ repeat 0
 {-# INLINE zeroPad #-}
 
 d :: Num a => [a] -> a
@@ -39,7 +39,7 @@
 d _ = 0
 {-# INLINE d #-}
 
-d2 :: Num a => [a] -> (a, a) 
+d2 :: Num a => [a] -> (a, a)
 d2 (a:da:_) = (a, da)
 d2 (a:_)    = (a, 0)
 d2 _        = (0, 0)
@@ -73,7 +73,7 @@
     Tower [] <+> bs = bs
     as <+> Tower [] = as
     Tower (a:as) <+> Tower (b:bs) = Tower (c:cs)
-        where 
+        where
             c = a + b
             Tower cs = Tower as <+> Tower bs
 
@@ -86,16 +86,16 @@
     type D Tower = Tower
     unary f dadb b = bundle (f (primal b)) (tangents b *! dadb)
     lift1 f df b   = bundle (f (primal b)) (tangents b *! df b)
-    lift1_ f df b = a where 
+    lift1_ f df b = a where
         a = bundle (f (primal b)) (tangents b *! df a b)
 
-    binary f dadb dadc b c = bundle (f (primal b) (primal c)) (tangents b *! dadb +! tangents c *! dadc) 
+    binary f dadb dadc b c = bundle (f (primal b) (primal c)) (tangents b *! dadb +! tangents c *! dadc)
     lift2 f df b c = bundle (f (primal b) (primal c)) (tangents b *! dadb +! tangents c *! dadc) where
-        (dadb, dadc) = df b c 
-    lift2_ f df b c = a where 
+        (dadb, dadc) = df b c
+    lift2_ f df b c = a where
         a0 = f (primal b) (primal c)
         da = tangents b *! dadb +! tangents c *! dadc
-        a = bundle a0 da 
+        a = bundle a0 da
         (dadb, dadc) = df a b c
 
 deriveLifted (conT ''Tower)
diff --git a/Numeric/AD/Newton.hs b/Numeric/AD/Newton.hs
--- a/Numeric/AD/Newton.hs
+++ b/Numeric/AD/Newton.hs
@@ -6,12 +6,12 @@
 -- License     :  BSD3
 -- Maintainer  :  ekmett@gmail.com
 -- Stability   :  experimental
--- Portability :  GHC only 
+-- Portability :  GHC only
 --
 -----------------------------------------------------------------------------
 
 module Numeric.AD.Newton
-    ( 
+    (
     -- * Newton's Method (Forward AD)
       findZero
     , inverse
@@ -29,30 +29,62 @@
 import Numeric.AD.Internal
 import Data.Foldable (all)
 import Data.Traversable (Traversable)
-import Numeric.AD.Forward (diff, diff2) 
-import Numeric.AD.Reverse (grad2) 
+import Numeric.AD.Forward (diff, diff2)
+import Numeric.AD.Reverse (grad2)
 
+-- | The 'findZero' function finds a zero of a scalar function using
+-- Newton's method; its output is a stream of increasingly accurate
+-- results.  (Modulo the usual caveats.)
+--
+-- Examples:
+--
+--  > take 10 $ findZero (\\x->x^2-4) 1  -- converge to 2.0
+--
+--  > module Data.Complex
+--  > 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
 {-# INLINE findZero #-}
 
+-- | The 'inverseNewton' function inverts a scalar function using
+-- Newton's method; its output is a stream of increasingly accurate
+-- results.  (Modulo the usual caveats.)
+--
+-- Example:
+--
+-- > take 10 $ inverseNewton sqrt 1 (sqrt 10)  -- converge to 10
+--
 inverse :: Fractional a => (forall s. Mode s => AD s a -> AD s a) -> a -> a -> [a]
 inverse f x0 y = findZero (\x -> f x - lift y) x0
 {-# INLINE inverse  #-}
 
+-- | The 'fixedPoint' function find a fixedpoint of a scalar
+-- function using Newton's method; its output is a stream of
+-- increasingly accurate results.  (Modulo the usual caveats.)
 fixedPoint :: Fractional a => (forall s. Mode s => AD s a -> AD s a) -> a -> [a]
 fixedPoint f = findZero (\x -> f x - x)
 {-# INLINE fixedPoint #-}
 
+-- | The 'extremum' function finds an extremum of a scalar
+-- function using Newton's method; produces a stream of increasingly
+-- accurate results.  (Modulo the usual caveats.)
 extremum :: Fractional a => (forall t s. (Mode t, Mode s) => AD t (AD s a) -> AD t (AD s a)) -> a -> [a]
 extremum f x0 = findZero (diff f) x0
 {-# INLINE extremum #-}
 
+-- | The 'gradientDescent' function performs a multivariate
+-- optimization, based on the naive-gradient-descent in the file
+-- @stalingrad\/examples\/flow-tests\/pre-saddle-1a.vlad@ from the
+-- VLAD compiler Stalingrad sources.  Its output is a stream of
+-- increasingly accurate results.  (Modulo the usual caveats.)
+--
+-- It uses reverse mode automatic differentiation to compute the gradient.
 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 gx0 0.1 (0 :: Int)
     where
         (fx0, gx0) = grad2 f x0
-        go x fx gx !eta !i 
+        go x fx gx !eta !i
             | eta == 0     = [] -- step size is 0
             | fx1 > fx     = go x fx gx (eta/2) 0 -- we stepped too far
             | all (==0) gx = [] -- gradient is 0
diff --git a/Numeric/AD/Reverse.hs b/Numeric/AD/Reverse.hs
--- a/Numeric/AD/Reverse.hs
+++ b/Numeric/AD/Reverse.hs
@@ -6,11 +6,11 @@
 -- License     :  BSD3
 -- Maintainer  :  ekmett@gmail.com
 -- Stability   :  experimental
--- Portability :  GHC only 
+-- Portability :  GHC only
 --
 -- Mixed-Mode Automatic Differentiation.
--- 
--- For reverse mode AD we use 'System.Mem.StableName.StableName' to recover sharing information from 
+--
+-- For reverse mode AD we use 'System.Mem.StableName.StableName' to recover sharing information from
 -- the tape to avoid combinatorial explosion, and thus run asymptotically faster
 -- than it could without such sharing information, but the use of side-effects
 -- contained herein is benign.
@@ -18,7 +18,7 @@
 -----------------------------------------------------------------------------
 
 module Numeric.AD.Reverse
-    ( 
+    (
     -- * Gradient
       grad
     , grad2
@@ -57,19 +57,19 @@
 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)
     where (vs, bds) = bind as
-          r = f vs 
+          r = f vs
 {-# INLINE grad2 #-}
 
 -- | 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)
-jacobian f as = unbind vs . partialArray bds <$> f vs where 
+jacobian f as = unbind vs . partialArray bds <$> f vs where
     (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,
 -- 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 
+jacobian2 f as = row <$> f vs where
     (vs, bds) = bind as
     row a = (primal a, unbind vs (partialArray bds a))
 {-# INLINE jacobian2 #-}
@@ -105,7 +105,7 @@
 
 -- | 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 
+diff = diffUU
 {-# INLINE diff #-}
 
 -- | The 'diff2' function is a synonym for 'diff2UU'.
diff --git a/Numeric/AD/Tower.hs b/Numeric/AD/Tower.hs
--- a/Numeric/AD/Tower.hs
+++ b/Numeric/AD/Tower.hs
@@ -6,14 +6,14 @@
 -- License     : BSD3
 -- Maintainer  : ekmett@gmail.com
 -- Stability   : experimental
--- Portability : GHC only 
+-- Portability : GHC only
 --
 -- Higher order derivatives via a \"dual number tower\".
 --
 -----------------------------------------------------------------------------
 
 module Numeric.AD.Tower
-    ( 
+    (
     -- * Taylor Series
       taylor, taylor0
     , maclaurin, maclaurin0
@@ -23,7 +23,7 @@
     , diffsUU
     , diffs0UU
     , diffsUF
-    , diffs0UF 
+    , diffs0UF
     -- * Synonyms
     , diffs, diffs0
     , diff, diff2
@@ -40,7 +40,7 @@
 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 
+diffsUU f a = getADTower $ apply f a
 {-# INLINE diffsUU #-}
 
 diffs0UU :: Num a => (forall s. Mode s => AD s a -> AD s a) -> a -> [a]
@@ -74,19 +74,19 @@
 {-# INLINE taylor0 #-}
 
 maclaurin :: Fractional a => (forall s. Mode s => AD s a -> AD s a) -> a -> [a]
-maclaurin f = taylor f 0 
+maclaurin f = taylor f 0
 {-# INLINE maclaurin #-}
 
 maclaurin0 :: Fractional a => (forall s. Mode s => AD s a -> AD s a) -> a -> [a]
-maclaurin0 f = taylor0 f 0 
+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 
+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 
+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 --git a/ad.cabal b/ad.cabal
--- a/ad.cabal
+++ b/ad.cabal
@@ -1,5 +1,5 @@
 Name:         ad
-Version:      0.12
+Version:      0.13
 License:      BSD3
 License-File: LICENSE
 Copyright:    Edward Kmett 2010
@@ -8,8 +8,11 @@
 Stability:    Experimental
 Category:     Math
 Homepage:     http://comonad.com/reader/
-Synopsis:     Mixed-Mode Automatic Differentiation.
-Description:  Forward, reverse, and higher-order automatic differentiation with a common API
+Synopsis:     Automatic Differentiation
+Description:  
+    Forward, reverse, and higher-order automatic differentiation combinators with a common API.
+    . 
+    Type-level \"branding\" is used to prevent the end user from confusing infinitesimals.
 
 Build-Type:   Simple
 Build-Depends:       
