所以我有一个双数字类:
data Dual a = !a :+ !a
instance [safe] Eq a => Eq (Dual a)
instance [safe] RealFloat a => Floating (Dual a)
instance [safe] RealFloat a => Fractional (Dual a)
instance [safe] RealFloat a => Num (Dual a)
instance [safe] Read a => Read (Dual a)
instance [safe] Show a => Show (Dual a)
现在,我想编写一个接受数字函数并将其派生为数字函数的函数。 (使用自动区分)。
这是我想出的:
{-# LANGUAGE FlexibleContexts #-}
autoDiff :: Floating a => (Dual a -> Dual a) -> a -> a
autoDiff f = dualPart . f . (flip (:+) 1)
现在以sin
为例,这就是我得到的:
*AutoDiff> :t sin
sin :: Floating a => a -> a
*AutoDiff> :t autoDiff sin
autoDiff sin :: RealFloat a => a -> a
*AutoDiff> :t autoDiff (autoDiff sin)
autoDiff (autoDiff sin) :: (RealFloat (Dual a), RealFloat a) => a -> a
*AutoDiff> sin 1
0.8414709848078965
*AutoDiff> (autoDiff sin) 1
0.5403023058681398
*AutoDiff> (autoDiff (autoDiff sin)) 1
<interactive>:109:1: error:
• No instance for (RealFloat (Dual a0)) arising from a use of ‘it’
• In a stmt of an interactive GHCi command: print it
我不知道错误消息告诉我什么。我曾尝试过使用forall
,但无法使用通用函数,无法通过它进行对偶运算并返回通用函数。
那么我该如何迭代autoDiff
以获得更高的导数,甚至在Haskell的类型系统中也有可能?
答案 0 :(得分:0)
您尝试:
autoDiff (autoDiff sin)
Haskell说:
No instance for (RealFloat (Dual a0)) arising from a use of ‘it’
现在我们可以问问它来自哪里,但是让我们写下我们拥有的类型,看看我们是否可以找出错误而不必查看错误内容:
autoDiff :: Num a => (Dual a -> Dual a) -> a -> a
sin :: Floating a => a -> a
计算autoDiff sin
时,必须使sin
与Dual a -> Dual a
统一,因此这需要Floating a
:
autoDiff sin :: (Floating (Dual a), Num a) => a -> a
现在您要服用autoDiff
,并且会发生同样的情况:
autoDiff (autoDiff sin) :: (Floating (Dual (Dual a)), Num a) => a -> a
现在,当您键入autoDiff (autoDiff sin) 1
时,Haskell确定它的类型为(Floating (Dual (Dual a)), Num a) => a
,但是需要选择一些a
来打印结果。它将先尝试Integer
,然后再尝试Double
,然后失败。
Haskell正在寻求满足约束Floating (Dual (Dual a))
,因此它寻找可以为Dual x
派生实例的所有方式,事实证明它需要RealFloat x
来做到这一点。因此,现在它已将约束从Floating (Dual (Dual a))
减少到RealFloat (Dual a)
,事实证明它无法派生RealFloat (Dual a)
的实例,因此无法编译。