2016-11-03 28 views
0
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 

此代碼預計爲工作如下:我有麻煩,在OCaml的製作差分功能(不是語法問題)

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

那麼輸出必須

Times[Const 2; Const 1] 

因爲如果我們區分2倍,結果是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 

爲什麼會發生此錯誤?我認爲有些地方是錯誤的,但我找不到任何邏輯錯誤。

回答

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)))) 

有了更加詳細,但understanble版本:

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 ([email protected]) 

現在是更具可讀性,而且你可以一一解決所有問題。另外,我建議不要試圖解決大胖子功能中的所有問題,而是將事物分解爲更易於處理的小函數,這也將解決您匹配內匹配的問題,例如,以下函數具有這樣的結構,但更易於理解:

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)) 
+0

謝謝你回答我。 我還在懷疑,我已經宣佈Times - > aexp list ,我認爲這意味着Times構造函數會生成aexp類型的列表。 我該如何解決這個問題..? –

+0

@송재민:'diff(Times t,var)'返回或返回產品總和。這是一個'aexp'結構'Sum',裏面有addens列表。將'Times'構造函數應用於'Sum'結構似乎是不合情理的。正確的結果應該像'diff(Times [u,v,w],x)= Sum [Times [u',v,w],Times [u,Sum [Times [v',w]五,總和[時報[W']]]]]]'。理想情況下,單元素和產品是解壓縮的... – LutzL

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)))