0

我已经看过这个ad包,我理解它是如何通过提供不同的实例class Floating然后实现衍生规则来自动区分的。

但是在示例中

Prelude Debug.SimpleReflect Numeric.AD> diff atanh x
recip (1 - x * x) * 1

我们看到它可以将函数表示为ASTs 并将它们显示为带有变量名的字符串。

我想知道他们是怎么做到的,因为当我写的时候:

f :: Floating a => a -> a
f x = x^2

无论我提供什么实例,我都会得到一个函数 f :: Something -> Something 而不是像f :: AST, 或f :: String

实例无法“知道”参数是什么。

他们是如何做到的?

4

1 回答 1

3

实际上,它与 AD 包无关,与xin diff atanh x.

为了看到这一点,让我们定义我们自己的 AST 类型

data AST = AST :+ AST
         | AST :* AST
         | AST :- AST
         | Negate AST
         | Abs AST
         | Signum AST
         | FromInteger Integer
         | Variable String

我们可以Num为这种类型定义一个实例

instance Num (AST) where
  (+) = (:+)
  (*) = (:*)
  (-) = (:-)
  negate = Negate
  abs = Abs
  signum = Signum
  fromInteger = FromInteger

还有一个Show实例

instance Show (AST) where
  showsPrec p (a :+ b) = showParen (p > 6) (showsPrec 6 a . showString " + " . showsPrec 6 b)
  showsPrec p (a :* b) = showParen (p > 7) (showsPrec 7 a . showString " * " . showsPrec 7 b)
  showsPrec p (a :- b) = showParen (p > 6) (showsPrec 6 a . showString " - " . showsPrec 7 b)
  showsPrec p (Negate a) = showParen (p >= 10) (showString "negate " . showsPrec 10 a)
  showsPrec p (Abs a) = showParen (p >= 10) (showString "abs " . showsPrec 10 a)
  showsPrec p (Signum a) = showParen (p >= 10) (showString "signum " . showsPrec 10 a)
  showsPrec p (FromInteger n) = showsPrec p n
  showsPrec _ (Variable v) = showString v

所以现在如果我们定义一个函数:

f :: Num a => a -> a
f a = a ^ 2

和一个 AST 变量:

x :: AST
x = Variable "x"

我们可以运行该函数来生成整数值或 AST 值:

λ f 5
25
λ f x
x * x

如果我们希望能够在您的函数中使用我们的 AST 类型f :: Floating a => a -> a; f x = x^2,我们需要扩展它的定义以允许我们实现Floating (AST)

于 2017-05-10T14:00:33.573 回答