Created
October 29, 2015 06:50
-
-
Save akabe/a16ed3bf95cf0d47e040 to your computer and use it in GitHub Desktop.
Static size checking for lists (loaded from files) by generative phantom types (functor version)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
(* http://akabe.github.io/2015/10/GenerativePhantomTypes *) | |
#load "str.cma";; | |
(** Loads a list of integers from a file of a given path (delimiters = spaces, | |
tabs, or line feeds). *) | |
let load_list fname = | |
let re = Str.regexp "[ \t]+" in | |
let oc = open_in fname in | |
let rec aux acc = try aux (input_line oc :: acc) with End_of_file -> acc in | |
aux [] | |
|> List.rev_map (Str.split re) | |
|> List.flatten | |
|> List.map int_of_string | |
module SizedList : sig | |
type 'n sized_list (** a type of lists of length ['n] (['n] is a phantom type | |
parameter, i.e., it does not appear in the r.h.s. of | |
the type definition) *) | |
type z (** a phantom type corresponding to zero *) | |
type 'n s (** a phantom type corresponding to successor (['n + 1]) *) | |
val nil : z sized_list | |
val cons : int -> 'n sized_list -> 'n s sized_list | |
val hd : 'n s sized_list -> int | |
val tl : 'n s sized_list -> 'n sized_list | |
val map : (int -> int) -> 'n sized_list -> 'n sized_list | |
val add : 'n sized_list -> 'n sized_list -> 'n sized_list | |
(** This functor has a type like [string -> (exists n. n sized_list)]. *) | |
module Load () (X : sig val fname : string end) : sig | |
type n | |
val x : n sized_list | |
end | |
end = struct | |
type 'n sized_list = int list | |
type z | |
type 'n s | |
let nil = [] | |
let cons x l = x :: l | |
let hd = List.hd | |
let tl = List.tl | |
let map = List.map | |
let add = List.map2 (+) | |
module Load () (X : sig val fname : string end) = struct | |
type n | |
let x = load_list X.fname | |
end | |
end | |
open SizedList | |
module M1 = Load()(struct let fname = "file" end) (* M1.x : M1.n sized_list *) | |
let y = map (fun a -> a * 2) M1.x (* y : M1.n sized_list *) | |
let z = add M1.x y (* well-typed because M1.x and y have the same length *) | |
module M2 = Load()(struct let fname = "file" end) (* M2.x : M2.n sized_list *) | |
let w = add M1.x M2.x (* ill-typed because M1.x and M2.x possibly have different | |
sizes (M1.n <> M2.n) *) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment