2009-12-02 56 views
3

我正在寫一個簡單的小型ocaml程序,它從文件中讀取代數語句,使用ocamllex/ocamlyacc將其解析爲AST,將其縮小並打印出來。我減少表情的部分似乎有點......很難看。有什麼辦法可以簡化它嗎?如何簡化這個ocaml模式匹配代碼?

(* ocaml doesn't seem to be able to take arithmetic operators 
as functions, so define these wrappers for them *) 
let add x y = 
    x + y 

let sub x y = 
    x - y 

let mul x y = 
    x * y 

let div x y = 
    x/y 

(* Are term1 and term2 both ints? *) 
let both_ints term1 term2 = 
    match (term1, term2) with 
    | (Term (Number x), Term (Number y)) -> true 
    | (_, _) -> false 

(* We know that both terms are reducable to numbers, so combine 
    them *) 
let combine_terms func x y = 
    match (x, y) with 
     (Term (Number t1), Term (Number t2)) -> 
     (Term (Number (func t1 t2))) 
    | (_, _) -> raise InvalidArg 

(* Reduce the expression as much as possible *) 
let rec reduce_expr expr = 
    match expr with 
     Plus (x, y) -> 
     let reduced_x = reduce_expr x 
     and reduced_y = reduce_expr y in 
     if both_ints reduced_x reduced_y then 
     (combine_terms add reduced_x reduced_y) 
     else 
     Plus (reduced_x, reduced_y) 
    | Minus (x, y) -> 
     let reduced_x = reduce_expr x 
     and reduced_y = reduce_expr y in 
     if both_ints reduced_x reduced_y then 
     (combine_terms sub reduced_x reduced_y) 
     else 
     Minus (reduced_x, reduced_y) 
    | Multiply (x, y) -> 
     let reduced_x = reduce_expr x 
     and reduced_y = reduce_expr y in 
     if both_ints reduced_x reduced_y then 
     (combine_terms mul reduced_x reduced_y) 
     else 
     Multiply (reduced_x, reduced_y) 
    | Divide (x, y) -> 
     let reduced_x = reduce_expr x 
     and reduced_y = reduce_expr y in 
     if both_ints reduced_x reduced_y then 
     (combine_terms div reduced_x reduced_y) 
     else 
     Divide (reduced_x, reduced_y) 
    | Term x -> Term x 
+7

注意ocaml的確實需要的算術運算符作爲函數:使用(/),(+)(*)和( - )...該()是強制性的,該空間只強制用於* – 2009-12-02 17:46:31

+0

僅供分析之用,menhir值得考慮。 http://cristal.inria.fr/~fpottier/menhir/ – LB40 2009-12-03 13:42:18

+0

其實,我一直在使用ocamlyacc,通常我會使用menhir,但是我想保持簡單的依賴。 – 2009-12-03 14:43:43

回答

6

可以刪除both_ints,和combine_terms功能以及一些if語句,通過匹配包含操作功能內Number,如類型:

let div x y = match x,y with 
    | Number x, Number y -> Number (x/y) 
    | _ -> Divide (x,y) 

... 
let rec reduce_expr expr = match expr with 
    ... 
    | Divide (x,y) -> div (reduce_expr x) (reduce_expr y) 
    ... 
+0

這是100%更清晰。謝謝! – 2009-12-02 19:29:56