OCaml-何时使用函子

OCaml-何时使用函子,ocaml,Ocaml,对于何时在代码中使用或实现函子,我有点困惑。我在下面包含了一些代码,其中有两个函数display_expr和cal_expr,这两个函数的形式相同,但实现方式不同。这是不是一个地方,我会考虑创建一个单一的函子,代表两个函数的核心功能? type expr = | Add of expr * expr | Minus of expr * expr | Multi of expr * expr | Divide of expr * expr | Value o

对于何时在代码中使用或实现函子,我有点困惑。我在下面包含了一些代码,其中有两个函数display_expr和cal_expr,这两个函数的形式相同,但实现方式不同。这是不是一个地方,我会考虑创建一个单一的函子,代表两个函数的核心功能?

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);;
注意:我尝试为上述代码编写了一个函子解决方案,当我发现函子需要一个公共类型或组合类型来表示display_expr和cal_expr返回的值时,我得到了一个解决方案


<>我也是一个极端的新手,所以请在你的回复中考虑。谢谢。

由于没有模块,函子在这里并不真正适用,但您可以直接使用高阶函数来攻击它

关键是要注意,每个构造函数需要一个转换,因此需要一个函数参数。此模式在某些方面类似于列表。向右折叠,可以将其视为替换列表构造函数的操作

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 a b = "(" ^ 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)

这是否比您的原始代码更可取是一个品味问题。

您的functor解决方案是什么样子的?我很难想象它,因为函子本质上是从一个模块到另一个模块的函数,而你给出的代码中没有任何模块。这是为了给我提供这样一个干净的解决方案。我真的很感激。在我看到你做了什么之前,我必须仔细检查你的代码。很好的解决方案。如果参数数量增加,您可以使用包含这些传递函数的实现的函子。或者创建一个包含所有这些函数的记录。但这对于问题的范围是有利的。