在 Haskell 中使用 Numeric.AD 时如何正确匹配类型?
How to properly match types when using Numeric.AD in Haskell?
我正在尝试使用 ad package, but I can't properly match function types. I know there's a proper answer to a similar question 实现 Newton–Raphson 求根算法,这是广告创建者自己回答的,但是自 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 returns出现如下错误:
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
,编译器会说它无法将 a
与 Forward a
匹配,而不是 a
与 [=20] =].我还尝试了几种从 x
创建双数以将其传递给 f
的方法,例如snd . unbundle . f $ bundle x 1
,但它只有在我使用它创建一个新的 g' x
时才有效,就像第一种情况一样。在 newton
中使用它也不起作用。
在Numeric.AD
、diff :: 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
一起使用的函数时我是否应该特别注意?最后,我应该如何更改我的代码以使其工作?我知道包 already has a function to find roots,但我还不想使用(因为我还在学习 Haskell),查看文档试图解决这个问题,感觉就像 运行 在圈子里。
观察你的函数:
newton :: Fractional a => (a -> a) -> a -> a
newton f x = x - (f x) / (diff f x)
在两个地方使用函数参数 f
。首先,
子表达式 f x
使用 f
和类型:
f :: Fractional a => a -> a
其次,由于使用了 diff
,子表达式 diff f x
使用了 f
,类型为:
f :: forall s a. Fractional a => AD s (Forward a) -> AD s (Forward a)
您收到的错误消息是类型系统观察到这些
类型不同,无法统一。
解决方法是显式量化newton
的函数参数
适用于满足适当数字类型 class 约束的所有类型。这需要 RankNTypes
语言扩展:
{-# LANGUAGE RankNTypes #-}
newton
:: Fractional a
=> (forall b. Fractional b => b -> b)
-> a
-> a
newton f x = x - (f x) / (diff f x)
我正在尝试使用 ad package, but I can't properly match function types. I know there's a proper answer to a similar question 实现 Newton–Raphson 求根算法,这是广告创建者自己回答的,但是自 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 returns出现如下错误:
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
,编译器会说它无法将 a
与 Forward a
匹配,而不是 a
与 [=20] =].我还尝试了几种从 x
创建双数以将其传递给 f
的方法,例如snd . unbundle . f $ bundle x 1
,但它只有在我使用它创建一个新的 g' x
时才有效,就像第一种情况一样。在 newton
中使用它也不起作用。
在Numeric.AD
、diff :: 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
一起使用的函数时我是否应该特别注意?最后,我应该如何更改我的代码以使其工作?我知道包 already has a function to find roots,但我还不想使用(因为我还在学习 Haskell),查看文档试图解决这个问题,感觉就像 运行 在圈子里。
观察你的函数:
newton :: Fractional a => (a -> a) -> a -> a
newton f x = x - (f x) / (diff f x)
在两个地方使用函数参数 f
。首先,
子表达式 f x
使用 f
和类型:
f :: Fractional a => a -> a
其次,由于使用了 diff
,子表达式 diff f x
使用了 f
,类型为:
f :: forall s a. Fractional a => AD s (Forward a) -> AD s (Forward a)
您收到的错误消息是类型系统观察到这些 类型不同,无法统一。
解决方法是显式量化newton
的函数参数
适用于满足适当数字类型 class 约束的所有类型。这需要 RankNTypes
语言扩展:
{-# LANGUAGE RankNTypes #-}
newton
:: Fractional a
=> (forall b. Fractional b => b -> b)
-> a
-> a
newton f x = x - (f x) / (diff f x)