模式匹配中的OCaml多态变体

时间:2017-07-26 23:21:38

标签: pattern-matching ocaml abstract-syntax-tree

我通过AST变换开发了一种小型编程语言。也就是说,从VM开始并慢慢添加帮助程序员的层。

由于每个图层都知道如何转换其新类型,我已经做过类似的事情:

module AST0 = struct

  type t = [
    | `Halt
    | `In
    | `Out
    | `Add of (int * int * int)
    | `Sub of (int * int * int)
  ]

  let lower (ast : t list) = ast
end

module AST1 = struct
  type t = [
    AST0.t

    | `Inc of int
    | `Dec of int 
    | `Cmp of (int * int * int)
  ]

  let lower (ast : t list) =
    let lower_one = function
      | `Inc a -> [`Add (a, a, `Imm 1)]
      | `Dec a -> [`Sub (a, a, `Imm 1)]
      | `Cmp (a, b) -> [`Sub (13, a, b)]
      | (x : AST0.t) -> AST0.lower [x]      (* <--- problem line *)
    in
    List.concat @@ List.map lower_one ast
end

不幸的是我收到错误:

File "stackoverflow.ml", line 28, characters 8-20:
Error: This pattern matches values of type AST0.t
       but a pattern was expected which matches values of type
         [? `Cmp of 'a * 'b | `Dec of 'c | `Inc of 'd ]
       The first variant type does not allow tag(s) `Cmp, `Dec, `Inc

我认为,因为编译器足够聪明,可以注意到我在任意匹配情况下都没有处理XY和Z变体,它可以告诉我x AST1.lower中的Cmp永远不会IncDec<?php public function actionPagination_product2(){ $tb_tab=Tablet::tableName(); Digital.inner_memory')->asArray()->all(); $data = Digital::find()->joinWith('tablet',true,'Left Join')->where('Tablet.sup_id = Digital.id')->asArray()->all(); $dataProvider = new ArrayDataProvider([ 'allModels' => $data, 'sort' => [ 'attributes' => ['id'], ], 'pagination' => [ 'pageSize' => 20, ], ]); return $this->render('pagination_pro2', [ 'dataProvider' => $dataProvider, ]); ?>中的一个。这似乎并非如此。

我是否误解了OCaml的类型系统?我错过了一些明显的东西吗这是一种愚蠢的方法吗?

1 个答案:

答案 0 :(得分:6)

您无法在本地约束案例模式的类型。类型约束: AST0.t也强制其他模式的类型为AST0.t。这就是为什么你的代码没有打字检查; `Inc中未包含AST0.t

然而,OCaml中有一个很好的功能,完全符合您的要求。 使用#AST0.t模式别名,而不是类型约束。有关详细信息,请参阅https://caml.inria.fr/pub/docs/manual-ocaml/lablexamples.html#sec46

  (* I fixed several other trivial typing problems *)
  let lower (ast : t list) =
    let lower_one = function
      | `Inc a -> [`Add (a, a, 1)]
      | `Dec a -> [`Sub (a, a, 1)]
      | `Cmp (a, b, c) -> [`Sub (13, a, b)]
      | #AST0.t as x -> AST0.lower [x]     (* <--- problem line *)
    in
    List.concat @@ List.map lower_one ast

#AST0.t as x不仅是(`Halt | `In | `Out | `And _ | `Sub _ as x)的缩写,还会将x右侧->的类型从[> AST1.t]更改为{{} 1}}。您可以将其用作[> AST0.t]