我在使用OCaml中的差异化功能时遇到了麻烦(不是关于语法问题)

时间:2016-11-03 17:12:45

标签: list ocaml differential-equations

  type aexp = 
  | Const of int
  | Var of string
  | Power of string * int
  | Times of aexp list
  | Sum of aexp list

  let rec diff : aexp * string -> aexp
  = fun (exp, var) -> 
    match exp with
    |Const a -> Const 0
    |Var x -> if x = var then Const 1 else Var x
    |Power (s, i) -> 
        if s = var then Times [Const i; Power (s, i - 1)] else Power (s, i)
    |Times l ->
        begin match l with
            |h::t -> Sum ((Times (diff (h, var) :: t)) @ (h :: Times (diff (Times t, var))))        
        end
    |Sum l ->
        begin match l with
            |h::t -> Sum (diff(h, var) :: diff(t, var))
        end

此代码预计可以如下工作:

diff (Times[Const 2; Var "x"], "x")

然后输出必须

Times[Const 2; Const 1]

因为如果我们区分2x,结果就是2

但是错误发生了,它说:

File "", line 18, characters 20-25:
Error: This variant expression is expected to have type 'a list
       The constructor Times does not belong to type list

为什么会出现这种错误?我认为有些地方是错的,但我找不到任何逻辑错误。

2 个答案:

答案 0 :(得分:2)

一些数学笔记:

  • 变量x不是x的变量的导数为零,而不是原始变量。

  • 对于不是x的变量的幂,它也是相对于x的常量。

  • 为什么只能使用变量(a+b)^i。更一般的情况就像特殊情况一样简单。

对于产品的衍生产品,考虑三个因素,并包括第一个递归步骤拆分uv*w

(u*v*w)' = u'*v*w + u*(v'*w+v*w')

在前缀表示法中,这可以写为

diff(*[u,v,w])=+[*[u',v,w],*[u,+[*[v',w],*[v,w']]]]

应该反映在

之类的内容中
|h::t -> Sum ((Times (diff (h, var) :: t)) @ (Times (h :: (diff (Times t, var)))))

作为双元素列表,这也可以写成

|h::t -> Sum ( Times (diff (h, var) :: t) , Times (h ,diff (Times t, var))) 

答案 1 :(得分:1)

让我们看看这个表达式:

h :: Times (diff (Times t, var))

为简单起见,请使用diff (Times t, var)替换dtdv,以便我们

h :: Times dtdv

::中缀构造函数要求其左侧的表达式应具有类型'a,而右侧的表达式应具有类型'a list的值。右侧的表达式为Times dtdv,构造函数Times创建类型为aexp的值,而不是类型列表的值。

顺便说一下,你还有两个错误和两个警告。这些错误属于同一类型,即您尝试在需要列表的位置应用aexp类型的值,即:

 Times (diff (h, var) :: t)) @ (h :: Times (diff (Times t, var))

让我们再次简化它

 Times (dhv::t) @ rest

@运算符需要双方列表,而Times something正如我们已经讨论的那样,不是列表。

看起来,您很难通过大量的括号和优先规则。我讨厌括号。所以,我总是谨慎地使用let ... in,例如,让我们重写以下表达式:

Sum ((Times (diff (h, var) :: t)) @ (h :: Times (diff (Times t, var))))

有一个更详细但不易讨厌的版本:

let h' = diff (h,var) in
let t' = diff (Times t,var) in
let lhs = Times (h'::t) in
let rhs = h :: Times t' in
Sum (lhs@rhs)

现在它更具可读性,您可以逐一解决所有问题。

另外,我建议不要尝试解决大胖函数中的所有问题,而是将事物分成更容易处理的小函数,这也可以解决匹配中匹配问题例如,以下函数的结构更容易理解:

let rec diff : aexp * string -> aexp = fun (exp, var) ->
    match exp with
    |Const a -> Const 0
    |Var x -> if x = var then Const 1 else Var x
    |Power (s, i) -> diff_power s i
    |Times l -> diff_times l
    |Sum l -> diff_sum l
and diff_power s i =
  if s = var then Times [Const i; Power (s, i - 1)] else Power (s, i)
and diff_times l = match l with
  |h::t -> Sum ((Times (diff (h, var) :: t)) @ (h :: Times (diff (Times t, var))))
and diff_sum l = match l with
  |h::t -> Sum (diff(h, var) :: diff(t, var))