我一直在努力实现自动差异化,从post
开始这就是我所拥有的,到目前为止的工作:
data DX a = DX { val :: a, dx :: DX a }
instance Num n => Num (DX n) where
fromInteger x = DX (fromInteger x) 0
DX x₀ x' + DX y₀ y' = DX (x₀ + y₀) (x' + y')
DX x₀ x' - DX y₀ y' = DX (x₀ - y₀) (x' - y')
x@(DX x₀ x') * y@(DX y₀ y') = DX (x₀ * y₀) (x * y' + y * x')
signum (DX x₀ x') = DX (signum x₀) 0
abs x@(DX x₀ x') = DX (abs x₀) (signum x * x')
instance Fractional n => Fractional (DX n) where
fromRational n = DX (fromRational n) 0
x@(DX x₀ x') / y@(DX y₀ y') =
DX (x₀ / y₀) ((x' * y - x * y') / y ^ 2)
instance Eq a => Eq (DX a) where
a == b = val a == val b
instance Ord a => Ord (DX a) where
compare a b = compare (val a) (val b)
instance Show a => Show (DX a) where
show (DX x (DX x' (DX x'' _))) = show [x, x', x'']
var x = DX x 1
然后,我试图定义牛顿的方法,这就是我陷入困境的地方:
newtons :: (Num a, Fractional a, Ord a) => a -> (a -> a) -> a -> a
newtons eps f guess
| abs (f guess) < eps = guess
| otherwise = newtons eps f newGuess
where
newGuess = guess - (x₀/x')
(DX x₀ (DX x' _)) = f (var guess)
我得到的错误是:
randomStuff.hs:75:34:
Couldn't match expected type ‘a’ with actual type ‘DX a’
‘a’ is a rigid type variable bound by
the type signature for
newtons :: (Num a, Fractional a) => a -> (a -> a) -> a -> a
at randomStuff.hs:69:12
Relevant bindings include
guess :: a (bound at randomStuff.hs:70:15)
f :: a -> a (bound at randomStuff.hs:70:13)
eps :: a (bound at randomStuff.hs:70:9)
newtons :: a -> (a -> a) -> a -> a (bound at randomStuff.hs:70:1)
In the first argument of ‘f’, namely ‘(var guess)’
In the expression: f (var guess)
我对此问题的理解如下:我已将给定函数推断为a -> a
类型,但我尝试以DX a -> DX a
形式使用它,不允许。
但是我应该能够以某种方式再次使用相同的函数,因为无论类型是什么,只要它在类型类Num
和Fractional
中就可以工作。
我的理解是否正确?我该如何解决这个问题?我需要Rank2Types吗?
答案 0 :(得分:0)
以下类型签名使其有效
newtons :: (Num a, Ord a, Fractional a) => a -> (forall b. (Num b, Ord b, Fractional b) => b -> b) -> a -> a
我可以运行:
*Main> newtons 0.001 (\x -> x^2 - 2) 2
1.4142156862745099
所以,是的,一种合理的解决方法是使用Rank2Types