针对构造函数的参数数量的模式匹配

Pattern matching against the number of arguments of a constructor

我想创建一个函数 inc,其工作方式如下:

type operation = MulNeg | Add n | Sub n
let ops = [Add 3; Add 4; Sub 2; MulNeg] in
let inc l = ... in
inc ops (* should return [Add 4; Add 5; Sub 3; MulNeg] *)

我知道我可以这样实现它:

let inc l = List.map (function 
    | MulNeg -> MulNeg
    | Add a -> Add (a + 1)
    | Sub a -> Sub (a + 1)
  ) l

但是在我的程序中有更多的操作,因此我的目标是拥有一个根据构造函数具有的参数数量运行的函数。我最接近的是这个:

let inc l = List.map (function
    | op a -> op (a + 1)
    | op -> op
  ) l

然而,这会在 op a 上引发错误。有合法的方法来制作这样的图案吗?

您不能对构造函数参数的数量进行模式匹配。 但是,您的问题的一个常见解决方案是引入一个额外的间接寻址,例如,

type binop = Add | Sub | Mul | Div
type unop = Inc | Dec | Ref
type exp = 
  | Const of int
  | Var of string
  | Unop of unop * exp
  | Binop of binop * exp * exp

let rec incr = function
  | Const x -> Const (x+1)
  | Var _ as v -> v
  | Binop (op,x,y) -> Binop (op,incr x, incr y)
  | Unop (op,x) -> Unop (op, incr x)

当然,当您的构造函数具有任意数量的参数时,这将无法扩展。然后您要么需要更改表示形式,要么坚持使用其他一些抽象。例如,Lisp-style 语言可以编码如下,

type prim = Add | Sub | Mul | Div
type op = Fun of string | Prim of prim
type exp = 
  | App of op * exp list
  | Atom of string

如果这两种解决方案都不适合您,那么您不应该使用代数数据类型,而是坚持访问者模式。