在OCaml中实现Array数据类型

时间:2017-06-07 23:09:09

标签: arrays types ocaml

我对OCaml整体知之甚少,只是收到了一个指定来获取项目中的一个源文件并允许它采用一种新的数据类型(Array)。我并不是要求有人为我解决这个问题,但我很感激有人带我走过这段代码。我还要感谢有关实现这种新数据类型的难度的任何意见。

文件本身缺少很多文档,这些文档也不容易。

(* * Types (hashconsed) *)

(* ** Imports *)
open Abbrevs
open Util

(* ** Identifiers *)

module Lenvar : (module type of Id) = Id

module Tysym : (module type of Id) = Id

module Groupvar : (module type of Id) = Id

module Permvar : (module type of Id) = Id


(* ** Types and type nodes *)

type ty = {
  ty_node : ty_node;
  ty_tag : int
}
and ty_node =
  | BS of Lenvar.id
  | Bool
  | G of Groupvar.id
  | TySym of Tysym.id
  | Fq
  | Prod of ty list
  | Int

(* ** Equality, hashing, and hash consing *)

let equal_ty : ty -> ty -> bool = (==)
let hash_ty t = t.ty_tag
let compare_ty t1 t2 = t1.ty_tag - t2.ty_tag

module Hsty = Hashcons.Make (struct
  type t = ty

  let equal t1 t2 =
    match t1.ty_node, t2.ty_node with
    | BS lv1, BS lv2                 -> Lenvar.equal lv1 lv2
    | Bool, Bool                     -> true
    | G gv1, G gv2                   -> Groupvar.equal gv1 gv2
    | TySym ts1, TySym ts2           -> Tysym.equal ts1 ts2
    | Fq, Fq                         -> true
    | Prod ts1, Prod ts2             -> list_eq_for_all2 equal_ty ts1 ts2
    | _                              -> false

  let hash t =
    match t.ty_node with
    | BS lv         -> hcomb 1 (Lenvar.hash lv)
    | Bool          -> 2
    | G gv          -> hcomb 3 (Groupvar.hash gv)
    | TySym gv      -> hcomb 4 (Tysym.hash gv)
    | Fq            -> 5
    | Prod ts       -> hcomb_l hash_ty 6 ts
    | Int           -> 7

  let tag n t = { t with ty_tag = n }
end)

(** Create [Map], [Set], and [Hashtbl] modules for types. *)
module Ty = StructMake (struct
  type t = ty
  let tag = hash_ty
end)
module Mty = Ty.M
module Sty = Ty.S
module Hty = Ty.H

(* ** Constructor functions *)

let mk_ty n = Hsty.hashcons {
  ty_node = n;
  ty_tag  = (-1)
}

let mk_BS lv = mk_ty (BS lv)

let mk_G gv = mk_ty (G gv)

let mk_TySym ts = mk_ty (TySym ts)

let mk_Fq = mk_ty Fq

let mk_Bool = mk_ty Bool

let mk_Int = mk_ty Int

let mk_Prod tys =
  match tys with
  | [t] -> t
  | _   -> mk_ty (Prod tys)

(* ** Indicator and destructor functions *)

let is_G ty = match ty.ty_node with
  | G _ -> true
  | _   -> false

let is_Fq ty = match ty.ty_node with
  | Fq -> true
  | _  -> false

let is_Prod ty = match ty.ty_node with
  | Prod _ -> true
  | _      -> false

let destr_G_exn ty =
  match ty.ty_node with
  | G gv -> gv
  | _    -> raise Not_found

let destr_BS_exn ty =
  match ty.ty_node with
  | BS lv -> lv
  | _     -> raise Not_found

let destr_Prod_exn ty =
  match ty.ty_node with
  | Prod ts -> ts
  | _       -> raise Not_found

let destr_Prod ty =
  match ty.ty_node with
  | Prod ts -> Some ts
  | _       -> None

(* ** Pretty printing *)

let pp_group fmt gv =
  if Groupvar.name gv = ""
  then F.fprintf fmt "G"
  else F.fprintf fmt "G_%s" (Groupvar.name gv)

let rec pp_ty fmt ty =
  match ty.ty_node with
  | BS lv             -> F.fprintf fmt "BS_%s" (Lenvar.name lv)
  | Bool              -> F.fprintf fmt "Bool"
  | Fq                -> F.fprintf fmt "Fq"
  | TySym ts          -> F.fprintf fmt "%s" (Tysym.name ts)
  | Prod ts           -> F.fprintf fmt "(%a)" (pp_list " * " pp_ty) ts
  | Int               -> F.fprintf fmt "Int"
  | G gv ->
    if Groupvar.name gv = ""
    then F.fprintf fmt "G"
    else F.fprintf fmt "G_%s" (Groupvar.name gv)

1 个答案:

答案 0 :(得分:1)

很难完成这段代码,因为缺少相当多的代码(Id,Hashcons,StructMake的定义)。但一般来说,这段代码操纵代表类型的数据结构。

你可以在这里阅读有关哈希的信息:https://en.wikipedia.org/wiki/Hash_consing(这就是我自己做的)。本质上,它是一种维持一组结构的规范表示的方式(在这种情况下,表示类型的结构),使得两个相等的结构(具有相同的组成部分)由相同的值表示。这允许对等式进行恒定时间比较。当你使用字符串执行此操作时,它被称为" interning" (来自Lisp的一种技术我曾经多次使用过。)

要添加数组,您需要知道数组类型是包含数组的长度还是包含其元素的类型。半神秘类型BS似乎包含一个长度,这表示您可能希望在您的代表中包含长度。

如果我正在做这个项目,我会寻找Prod(代表元组)的每一次出现,我会以类似的方式添加一个代表Array的类型。而不是组成类型列表(对于元组),你有一个组成类型和(我猜)一个表示数组长度的变量。

在开始之前,我会查找一些文档,关于BS代表一件事。我也不知道" group"是的,但也许你以后可能会担心。

<强>更新

以下是复制Prod的含义。请记住,我几乎完全基于猜测。因此,许多细节(甚至整个想法)都可能是错误的。

类型的当前定义如下所示:

and ty_node =
  | BS of Lenvar.id
  | Bool
  | G of Groupvar.id
  | TySym of Tysym.id
  | Fq
  | Prod of ty list
  | Int

如果您在Array之后添加Prod的代表,则可以获得以下内容:

and ty_node =
  | BS of Lenvar.id
  | Bool
  | G of Groupvar.id
  | TySym of Tysym.id
  | Fq
  | Prod of ty list
  | Array of Lenvar.id * ty
  | Int

然后,您将浏览其余代码,添加对新Array变体的支持。编译器将帮助您找到许多需要修复的地方。