練習問題 6.11

上の arith から、その数式の文字列表現を求める関数 string_of_arith、分配則を用いて数式を (i11 X … X i1n1_ + … + (im1 X … X imnm) (ただし ixy は整数)の形に変形する関数 expand を定義しなさい。
string_of_arith exp;;
: string = “((3 + 4) * (2 + 5))”
string_of_arith (expand exp);;
: string = “(((3 * 2) + (3 * 5)) + ((4 * 2) + (4 * 5)))”
簡単だと思う人は、string_of_arith の出力結果のカッコを減らすように工夫しなさい。

解答

(* arith の定義 *)
type arith =
    Const of int |Add of arith * arith | Mul of arith * arith;;

let exp = Mul (Add ( Const 3, Const 4), Add ( Const 2, Const 5));;

(* 数式の文字列表現 *)
let rec string_of_arith e =
    match e with
    Const v -> string_of_int v
    | Add (v1, v2) -> "(" ^ string_of_arith v1 ^ "+" ^ string_of_arith v2 ^ ")"
    | Mul (v1, v2) -> "(" ^ string_of_arith v1 ^ "*" ^ string_of_arith v2 ^ ")";;

(* 分配則 -- まだ、不十分 *)
let expand e =
    match e with
    Const v -> Const v
    | Add (v1, v2) -> Add (v1, v2)
    | Mul (v1, v2) -> 
            match (v1, v2) with
            (Add(x1, x2), Add(y1, y2)) ->
                Add( Add (Mul (x1, y1), Mul (x1, y2)),
                     Add (Mul (x2, y1), Mul (x2, y2)));;

expand は、すべての場合を網羅できていないが、とりあえず、問題文の形にはなった。