[Haskell-cafe] Safe forward-mode AD in Haskell?

David Roundy droundy at darcs.net
Tue May 8 21:44:00 EDT 2007


Okay, here's an alternate, unbranded approach:

> data Bundle a = Bundle a a

> instance Num a => Show (Bundle a) where
>   showsPrec p (Bundle x x') = showsPrec p [x,x']

> instance Num a => Eq (Bundle a) where
>   (Bundle x x') == (Bundle y y') = (x == y)

> instance Num a => Num (Bundle a) where
>   (Bundle x x') + (Bundle y y') = Bundle (x + y) (x' + y')
>   (Bundle x x') * (Bundle y y') = Bundle (x * y) (x * y' + x' * y)
>   fromInteger z = Bundle (fromInteger z) 0

> lift z = Bundle z 0

> d :: Num a => (forall b. (Num b) => (a -> b) -> b -> b) -> a -> a
> d f x = let (Bundle y y') = f lift (Bundle x 1) in y'

The key change is in the type of d, which now accepts a polymorphic
function on numbers, but passes in a "lift" function, which allows us to
pass in higher-level variables.  In one sense this function is ugly.  In
another sense, it's prettier, as you can now hide *all* of the Bundle data
in a "differentiation" module.

> constant_one x = d (\l y -> l x + y) 1

> should_be_one_a = d (\_ x -> x * (constant_one x)) 1
> should_be_one_b = d (\_ x -> x * 1 ) 1

> violation_of_referential_transparency =
>     should_be_one_a /= should_be_one_b

-- 
David Roundy
Department of Physics
Oregon State University


More information about the Haskell-Cafe mailing list