OCaml - When to Use Functors

I am a little confused about when to use or implement functors in one code. I have included some code below that has two display_expr, cal_expr functions, and both of these functions have the same form, but differ in implementation. Will this be the place where I would like to consider creating one functor, which will be the main functionality of both functions?

type expr = | Add of expr * expr | Minus of expr * expr | Multi of expr * expr | Divide of expr * expr | Value of int;; let rec display_expr e = match e with | Add (a1, a2) -> "(" ^ display_expr a1 ^ " + " ^ display_expr a2 ^ ")" | Minus (m1, m2) -> "(" ^ display_expr m1 ^ " - " ^ display_expr m2 ^ ")" | Multi (m1, m2) -> "(" ^ display_expr m1 ^ " * " ^ display_expr m2 ^ ")" | Divide (d1, d2) -> "(" ^ display_expr d1 ^ " / " ^ display_expr d2 ^ ")" | Value v -> string_of_int v;; let rec cal_expr e = match e with | Add (a1, a2) -> (cal_expr a1) + (cal_expr a2) | Minus (m1, m2) -> (cal_expr m1) - (cal_expr m2) | Multi (m1, m2) -> (cal_expr m1) * (cal_expr m2) | Divide (d1, d2) -> (cal_expr d1) / (cal_expr d2) | Value v -> v;; let equ = Multi(Value 34, Add(Value 24, Divide(Value 24, Minus(Value 10, Value 7) ) ) );; Printf.fprintf stdout "%d = %s\n" (cal_expr equ) (display_expr equ);; 

Note. I tried to write a solution for the above code, and I got one working as soon as I found out that the functor required a common or combined type for the values ​​returned by display_expr and cal_expr.

Also: I am an extreme OCaml rookie, so please think about this in your answer. Thank you.

+6
source share
1 answer

Functors do not really apply here, since there are no modules, but you can attack this completely directly with higher-order functions.

The key is to note that each constructor requires one transformation and, therefore, one function argument. This pattern is similar in some cases to List.fold_right , which can be thought of as an operation that replaces list constructors.

 type expr = | Add of expr * expr | Sub of expr * expr | Mul of expr * expr | Div of expr * expr | Int of int let transform ~add ~sub ~mul ~div ~int expr = let rec tx = function | Add (x, y) -> add (tx x) (tx y) | Sub (x, y) -> sub (tx x) (tx y) | Mul (x, y) -> mul (tx x) (tx y) | Div (x, y) -> div (tx x) (tx y) | Int x -> int x in tx expr let binary_op_str sep ab = "(" ^ a ^ sep ^ b ^ ")" let display_expr = transform ~add:(binary_op_str " + ") ~sub:(binary_op_str " - ") ~mul:(binary_op_str " * ") ~div:(binary_op_str " / ") ~int:string_of_int let cal_expr = transform ~add:(+) ~sub:(-) ~mul:( * ) ~div:(/) ~int:(fun x -> x) 

Whether this is preferred by your source code is a bit of a taste.

+4
source

All Articles