5

I'm having little success wrapping my head around the basic plumbing of the types involved in the ad package. For example, the following works perfectly:

import Numeric.AD

ex :: Num a => [a] -> a
ex [x, y] = x + 2*y

> grad ex [1.0, 1.0]
[1.0, 2.0]

where grad has the type:

grad
  :: (Num a, Traversable f) =>
     (forall (s :: * -> *). Mode s => f (AD s a) -> AD s a)
     -> f a -> f a

If I change the type signature of ex to [Double] -> Double and try the same thing, I get

Couldn't match expected type `AD s a0' with actual type `Double'
Expected type: f0 (AD s a0) -> AD s a0
  Actual type: [Double] -> Double

The same behaviour occurs when replacing Double with seemingly any type constructor with kind * that instantiates Num.

When the Traversable f is a list, the first argument of grad must have type [AD s a] -> AD s a for some acceptable Mode - e.g., Reverse. But clearly the user of grad doesn't have to deal with the AD constructor or the Mode directly. Peeking into these internals have left me a bit confused; specifically, I can't follow the kind/type trail to the difference between using Num a => [a] -> a and [Double] -> Double.

Why does the type signature [Double] -> Double cause problems with grad? And in terms of plain old library use: is there any way to use the [Double] -> Double version of ex, or is a polymorphic version necessary?

(title inspired by this similar question)

Community
  • 1
  • 1
jtobin
  • 3,253
  • 3
  • 18
  • 27

1 Answers1

6

I don't know the ad library, but since grad expects a function of type [AD s a] -> AD s a as its first parameter, you cannot expect to be able to pass it a function of type [Double] -> Double, since Double and AD are completely different types.

The generic function with Num constraint works, because AD itself is also an instance of Num, therefore in your working example, ex gets specialized to something like

ex :: (Mode s, Fractional a) => [AD s a] -> AD s a

If you want to specialize ex for calculations using Doubles, you need to give it a signature such as

ex :: Mode s => [AD s Double] -> AD s Double
shang
  • 24,642
  • 3
  • 58
  • 86
  • Ahhhh ok, so `AD` is an instance of `Num`. I failed to notice that in the instances list, but I see it now. – jtobin Jul 25 '12 at 19:56
  • 2
    Also, if you have some constants lying around as Doubles, say, in other data structures, you may need to use Numeric.AD.Types.lift or the other combinators in Mode to have them interact with your AD s Double arguments and result. – Edward Kmett Jul 28 '12 at 09:23