在Ocaml中定义lambda表达式的类型

时间:2011-09-10 04:27:03

标签: types ocaml

对于练习,我试图定义一个对应于由变量,抽象和应用程序组成的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")应视为有效。

4 个答案:

答案 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,其中每个VarAbsApp

Abs牵引力应该由变量和表达式组成,而不是两个表达式。在这种情况下,变量只是一个字符串,因此Abs应该由字符串和表达式组成。

将其更改为:

Abs of string * expr