1.7 数式の記号処理

このチュートリアルの最後に、Caml の記号処理の使い方を代表するようなもっと完全な例として、変数を含む算術式の処理を示します。以下のようなバリアント型で処理する式を表します。

#type expression =
     Const of float
   | Var of string
   | Sum of expression * expression    (* e1 + e2 *)
   | Diff of expression * expression   (* e1 - e2 *)
   | Prod of expression * expression   (* e1 * e2 *)
   | Quot of expression * expression   (* e1 / e2 *)
 ;;
type expression =
    Const of float
  | Var of string
  | Sum of expression * expression
  | Diff of expression * expression
  | Prod of expression * expression
  | Quot of expression * expression
    

まず最初に変数と値を対応づける環境を与えて式を評価する関数を定義します。簡単のために、環境は連想リストで表すことにします。

#exception Unbound_variable of string;;
exception Unbound_variable of string

#let rec eval env exp =
   match exp with
     Const c -> c
   | Var v ->
       (try List.assoc v env with Not_found -> raise(Unbound_variable v))
   | Sum(f, g) -> eval env f +. eval env g
   | Diff(f, g) -> eval env f -. eval env g
   | Prod(f, g) -> eval env f *. eval env g
   | Quot(f, g) -> eval env f /. eval env g;;
val eval : (string * float) list -> expression -> float = <fun>

#eval [("x", 1.0); ("y", 3.14)] (Prod(Sum(Var "x", Const 2.0), Var "y"));;
- : float = 9.42
    

次に、本当の記号処理として、変数 dv に関する式の微分を定義します。

#let rec deriv exp dv =
   match exp with
     Const c -> Const 0.0
   | Var v -> if v = dv then Const 1.0 else Const 0.0
   | Sum(f, g) -> Sum(deriv f dv, deriv g dv)
   | Diff(f, g) -> Diff(deriv f dv, deriv g dv)
   | Prod(f, g) -> Sum(Prod(f, deriv g dv), Prod(deriv f dv, g))
   | Quot(f, g) -> Quot(Diff(Prod(deriv f dv, g), Prod(f, deriv g dv)),
                        Prod(g, g))
 ;;
val deriv : expression -> string -> expression = <fun>

#deriv (Quot(Const 1.0, Var "x")) "x";;
- : expression =
Quot (Diff (Prod (Const 0., Var "x"), Prod (Const 1., Const 1.)),
 Prod (Var "x", Var "x"))