在 Haskell 中使用 Numeric.AD 时如何正确匹配类型?



我正在尝试使用广告包实现牛顿-拉夫森寻根算法,但我无法正确匹配函数类型。我知道类似的问题有一个正确的答案,这个问题是由广告的创建者自己回答的,但是自 1.0.6 版(当前版本是 4.3.4(以来,软件包发生了很大变化。

当我迭代它时,第一个最小示例编译并工作:

import Numeric.AD
import Numeric.AD.Internal.Forward
g :: Fractional a => a -> a
g x = - x + 2
g' :: Fractional a => a -> a
g' x = diff g x
newtonG :: Fractional a => a -> a
newtonG x = x - (g x) / (g' x)

但是如果我尝试抽象函数,如下所示:

import Numeric.AD
import Numeric.AD.Internal.Forward
g :: Fractional a => a -> a
g x = - x + 2
newton :: Fractional a => (a -> a) -> a -> a
newton f x = x - (f x) / (diff f x)

GHC 返回以下错误:

fsolve.hs:8:32: error:
* Couldn't match type `a' with `AD s (Forward a)'
`a' is a rigid type variable bound by
the type signature for:
newton :: forall a. Fractional a => (a -> a) -> a -> a
at fsolve.hs:7:11
Expected type: AD s (Forward a) -> AD s (Forward a)
Actual type: a -> a
* In the first argument of `diff', namely `f'
In the second argument of `(/)', namely `(diff f x)'
In the second argument of `(-)', namely `(f x) / (diff f x)'
* Relevant bindings include
x :: a (bound at fsolve.hs:8:10)
f :: a -> a (bound at fsolve.hs:8:8)
newton :: (a -> a) -> a -> a (bound at fsolve.hs:8:1)

如果我用Numeric.AD.Rank1.Forward而不是Numeric.AD,编译器说它不能aForward a匹配,而不是aAD s (Forward a)匹配。我还尝试了几种从x创建双数以将其传递给f的方法,例如snd . unbundle . f $ bundle x 1,但它只有在我使用它创建新g' x时才有效,就像第一种情况一样。在newton中使用它也不起作用。

Numeric.ADdiff :: Num a => (forall s. AD s (Forward a) -> AD s (Forward a)) -> a -> a.而在Numeric.AD.Rank1.Forward,它是diff :: Num a => (Forward a -> Forward a) -> a -> a。那么,为什么它们在第一种情况下接受a -> a类型的函数,而在第二种情况下则不接受呢?除了使用多态函数外,在创建与Numeric.AD一起使用的函数时,我是否应该特别小心?最后,我应该如何更改我的代码以使其正常工作?我知道该软件包已经具有查找根的功能,但我还不想使用(因为我仍在学习 Haskell(,并且查看文档试图解决这个问题,感觉就像在绕圈子。

观察你的函数:

newton :: Fractional a => (a -> a) -> a -> a
newton f x = x - (f x) / (diff f x)

在两个位置f使用函数参数。 首先, 子表达式f xf与以下类型一起使用:

f :: Fractional a => a -> a

其次,由于使用了diff子表达式diff f xf与类型一起使用:

f :: forall s a. Fractional a => AD s (Forward a) -> AD s (Forward a)

您收到的错误消息是类型系统观察到这些 是无法统一的不同类型。

解决方案是显式量化newton的函数参数 适用于满足相应数值类型类约束的所有类型。 这需要RankNTypes语言扩展:

{-# LANGUAGE RankNTypes #-}
newton
:: Fractional a
=> (forall b. Fractional b => b -> b)
-> a
-> a
newton f x = x - (f x) / (diff f x)

相关内容

  • 没有找到相关文章

最新更新