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 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 返回的值的通用或组合类型,我就开始工作了。

另外:我是一个极端的 OCaml 菜鸟,所以请在您的回复中考虑这一点。谢谢。

最佳答案

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

关键是要观察到每个构造函数都需要一个转换,因此需要一个函数参数。这种模式在某些方面类似于 List.fold_right ,可以认为是替换列表构造函数的操作。

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)

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

关于OCaml - 何时使用仿函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21224539/

相关文章:

ocaml - 尝试通过 Lwt 教程,但似乎存在库问题

module - OCaml 中的嵌套签名示例?

haskell - 将 ML 风格的模块添加到 Haskell 的主要理论困难是什么?

ocaml - 在 OCamlyacc 中使用外部类型声明

compilation - 如何获得最小的 ocamlopt 编译的 native 二进制文件?

syntax-error - 仿函数中的 OCaml 语法错误

ocaml - 复杂数据结构 ocaml 上的模式匹配

interface - OCaml 接口(interface)与签名?

design-patterns - OCaml 中的访问者设计模式

algorithm - 函数类型中的ocaml如何使用匹配?