对于练习,我试图定义一个对应于由变量,抽象和应用程序组成的lambda-calculus表达式的类型。我目前最好的尝试是:
type expr = Var of string | Abs of expr * expr | App of expr * expr
但是,我想将Abs
的第一部分限制为Var
。例如,我希望这是一个不正确的expr:
Abs(Abs(Var "foo", Var "bar"), Var "bar")
但目前已被视为有效。我还要求App
的第一部分是Abs
。有没有办法让类型系统强制执行这些限制,或者这是否超出了它的设计范围?
编辑:如果不清楚,Abs(Var "x", Var "x")
应视为有效。
答案 0 :(得分:4)
你不能让类型系统直接强制执行类似的东西。相反,我会考虑定义两种类型:
type variable = Name of string
type expr = Var of variable | Abs of variable * expr | App of expr * expr
这类似于Jeff的答案,但是您可以自由地更改用于定义变量的类型,而无需担心在两个位置更改它。两者都是处理问题的有效方法。
答案 1 :(得分:2)
AFAIU,您需要GADT来实现这一点,最近已合并到svn trunk中。
这是业余的例子(可能不完全正确,但它满足您的要求):
OCaml version 3.13.0+dev6 (2011-07-29)
# type _ t =
| Var : string -> string t
| Abs : (string t * 'a t) -> (string * 'a) t
| App : ((string * 'a) t * 'b t) -> ('a -> 'b) t;;
type 'a t =
Var : string -> string t
| Abs : (string t * 'b t) -> (string * 'b) t
| App : ((string * 'c) t * 'd t) -> ('c -> 'd) t
# Abs(Abs(Var "foo", Var "bar"), Var("bar"));;
Error: This expression has type (string * 'a) t
but an expression was expected of type string t
# App(Var "bar", Abs(Var "foo", Var "bar"));;
Error: This expression has type string t
but an expression was expected of type (string * 'a) t
# App(Abs(Var "foo", Var "bar"), Var("bar"));;
- : (string -> string) t = App (Abs (Var "foo", Var "bar"), Var "bar")
答案 2 :(得分:2)
Polymorphic variants允许您定义数据类型的子类型。子类型强制执行简单的结构约束。
例如,这里是一个带有多态变体的lambda项的定义,带有头部正规形式的子类型的定义。
type var = [ `Var of string ]
type expr = [
| var
| `Abs of var * expr
| `App of expr * expr
]
type irr (*non-head-reducible applications*) = [
| var
| `App of irr * expr
]
type hnf (*head normal forms*) = [
| irr
| `Abs of var * hnf
]
let substitution (x : var) (u : expr) : expr -> expr =
failwith "left as an exercise"
(*Iterated head reductions produce a head normal form*)
let rec head_reductions : expr -> hnf = function
| #var as x -> x
| `Abs (x, u) -> `Abs (x, head_reductions u)
| `App (u, v) ->
match head_reduction u with
| #irr as u -> u
| `Abs (x, w) -> head_reductions (substitution x u (w :> expr))
答案 3 :(得分:1)
问题是您已定义Abs
接受两个expr
,其中每个Var
,Abs
或App
。
Abs
牵引力应该由变量和表达式组成,而不是两个表达式。在这种情况下,变量只是一个字符串,因此Abs
应该由字符串和表达式组成。
将其更改为:
Abs of string * expr