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
両方のタイプで動作する関数の table-or-array のような種類が必要ですが、テーブルでrawgeti
(配列操作) などを禁止することもできます。objlen
スタックの一番上にある要素の「長さ」を返すスタック操作です。この要素は、テーブルまたは配列テーブルの両方にすることができます。現時点では、ラッパー関数は次のように定義されています。
val objlen : (top table) t -> int
私が欲しいのは
val objlen : (top table-or-array) t -> int
つまり、array
とtable
は のサブタイプですtable-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 は任意のタイプのスタックにプッシュします。