Как я могу упростить этот код сопоставления с образцом ocaml? - PullRequest
4 голосов
/ 02 декабря 2009

Я пишу простую небольшую программу ocaml, которая считывает алгебраическое утверждение из файла, анализирует его в AST с помощью ocamllex / ocamlyacc, уменьшает его и затем печатает. Та часть, где я уменьшаю выражение, кажется немного ... некрасивой. Можно ли как-нибудь это упростить?

(* 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

1 Ответ

6 голосов
/ 02 декабря 2009

Вы можете удалить функции 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)
    ...
...