2

所以我有一个双数课程:

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

4

1 回答 1

0

你试试:

autoDiff (autoDiff sin)

哈斯克尔说:

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))to的约束RealFloat (Dual a),结果证明它没有办法派生一个实例,RealFloat (Dual a)所以它无法编译。

于 2018-08-06T20:44:19.190 回答