我几乎没有成功地绕着ad
包中涉及的类型的基本管道。例如,以下工作完美:
import Numeric.AD
ex :: Num a => [a] -> a
ex [x, y] = x + 2*y
> grad ex [1.0, 1.0]
[1.0, 2.0]
其中grad
的类型为:
grad
:: (Num a, Traversable f) =>
(forall (s :: * -> *). Mode s => f (AD s a) -> AD s a)
-> f a -> f a
如果我将ex
的类型签名更改为[Double] -> Double
并尝试相同的操作,我会
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
将Double
替换为具有实例化*
的类型Num
的任何类型构造函数时,会发生相同的行为。
当Traversable f
是列表时,grad
的第一个参数必须为某些可接受的Mode
类型[AD s a] -> AD s a
- 例如Reverse
。但很明显grad
的用户无需直接处理AD
构造函数或Mode
。窥视这些内部结构让我有些困惑;具体来说,我无法遵循使用Num a => [a] -> a
和[Double] -> Double
之间的差异/类型跟踪。
为什么类型签名[Double] -> Double
会导致grad
出现问题?就简单的旧库使用而言:有没有办法使用[Double] -> Double
ex
版本,或者是必需的多态版本?
(标题灵感来自this similar question)
答案 0 :(得分:6)
我不知道ad
库,但由于grad
期望类型为[AD s a] -> AD s a
的函数作为其第一个参数,因此您不能指望将其传递给它类型为[Double] -> Double
的函数,因为Double
和AD
是完全不同的类型。
Num
约束的泛型函数有效,因为AD
本身也是Num
的一个实例,因此在您的工作示例中,ex
专门用于类似< / p>
ex :: (Mode s, Fractional a) => [AD s a] -> AD s a
如果你想使用双打专门化ex
进行计算,你需要给它一个签名,例如
ex :: Mode s => [AD s Double] -> AD s Double