2017-07-26 96 views
4

我正在通過AST變換增長一種小型編程語言。也就是說,從虛擬機開始,慢慢添加一些幫助程序員的層。模式匹配中的OCaml多態變體

由於每一層都知道如何將其新的類型,我做了這樣的事情:

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變體,它可以說明xAST1.lower將永遠不會是CmpIncDec之一。這似乎並非如此。

我誤解了OCaml的類型系統嗎?我錯過了明顯的東西嗎?這是一種愚蠢的做法嗎?

回答

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][> AST0.t]類型。你可以在那裏用它作爲AST0.t

+0

所以這似乎已經修復了我的一個層,但沒有另一個。我現在正在考慮... – tekknolagi

+0

正如我預料的那樣,另一層因爲我做了一些愚蠢的事情而被打破了。感謝您的幫助! – tekknolagi