如何在Haskell中实现自动区分?

时间:2018-08-01 12:44:37

标签: haskell types automatic-differentiation

所以我有一个双数字类:

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的类型系统中也有可能?

1 个答案:

答案 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时,必须使sinDual 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)的实例,因此无法编译。