
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