OCaml中的高阶类型(幻像类型子类型)

时间:2013-06-07 20:07:20

标签: ocaml higher-kinded-types phantom-types

我正在使用幻像类型来模拟堆栈的状态,作为ocaml-lua的包装模块(Lua通过堆栈与C / OCaml通信)。小代码示例:

type 's t
type empty
type 's table
type top

val newstate : unit -> empty t           (* stack empty *)
val getglobal : empty t -> top table t   (* stack: -1 => table *)

在表和数组表上都可以进行某些堆栈操作(Lua中没有真正的数组);有些不是。所以,如果我有类型

type 's table
type 's array

我想要一种类似于表或数组的函数,这些函数可以在两种类型上运行,但仍然可以禁止例如表上的rawgeti(数组操作)。 objlen是一个堆栈操作,它返回堆栈顶部元素的“长度”。该元素可以是table或array-table。目前,包装函数定义如下:

val objlen : (top table) t -> int

我想要的是

val objlen : (top table-or-array) t -> int

arraytabletable-or-array的子类型。

有什么想法吗?

此致 欧莱

修改

经过考虑后,我想出了这个:

module M : sig
  type ('s, 't) t

  (* New Lua state with empty stack *)
  val newstate : unit -> (unit, unit) t

  (* Get table *)
  val getglobal : ('a) t -> ([< `table | `string | `number | `fn], 'a) t

  (* Get array index and put "anything" on top of stack *)
  val rawgeti : ([`table], 'a) t -> ([< `table | `string | `number | `fn], [`table] * 'a) t

  (* String on top of stack *)
  val tostring : ([`string], _) t -> string

  (* Table or array-table on top of stack *)
  val objlen : ([`table], _) t -> int

  val pop : ('a, 'b * 'c) t -> ('b, 'c) t
end = struct
  type top
  type ('s, 't) t = string      (* Should really be Lua_api.Lua.state *)

  (* Dummy implementations *)
  let newstate () = "state"
  let gettable s = s
  let getarray s = s
  let rawgeti s = s
  let tostring s = "Hello phantom world!"
  let objlen s = 10
  let pop s = s
end

类型级别的堆栈现在应该既不知道堆栈本身也不知道堆栈本身。例如。 rawgeti将推送任何类型的堆栈。

1 个答案:

答案 0 :(得分:3)

以下结构怎么样?

type ('data, 'kind) t
type array_kind
type stack_kind

(* use tuples as type-level lists:
   (a * (b * (c * unit))) for the stack of type-shape [a;b;c] *)
val newstate : unit -> (unit, stack) t
val getglobal : (unit, stack) t -> (top * unit, stack) t

val objlen : (top * 'a, 'k) t -> int

这使用多态(在'k上)表达“任何类型 使用多态变体,可以使用子类型 相反,但我宁愿建议反对它,因为它更多 复杂及其与GADT的交互(您想要使用它) 在内部实现您的幻像类型签名,或者可能 直接暴露GADTs)更成问题。

PS:这正是标准Bigarray模块出于类似目的使用“种类”的方式。

编辑:上面的公式有点尴尬,因为多态变体也使用多态(在特定情况下使用子类型),并且只能在类型级变体中使用多态。我对这个解决方案过于复杂的评论仍然存在。