我对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
当用实例化Num
的 kind *
替换Double
看似任何类型的构造函数时,也会发生相同的行为。
当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
,还是需要多态版本?
(标题灵感来自这个类似的问题(
我不知道ad
库,但由于grad
期望将 [AD s a] -> AD s a
类型的函数作为其第一个参数,因此您不能期望能够向它传递 [Double] -> Double
类型的函数,因为Double
和AD
是完全不同的类型。
具有Num
约束的泛型函数有效,因为AD
本身也是Num
的实例,因此在您的工作示例中,ex
专门用于类似
ex :: (Mode s, Fractional a) => [AD s a] -> AD s a
如果要专门ex
使用双精度进行计算,则需要为其提供签名,例如
ex :: Mode s => [AD s Double] -> AD s Double