Created
October 29, 2015 07:19
-
-
Save akabe/53ad9e17f9550ce5d0bc to your computer and use it in GitHub Desktop.
Static size checking for lists (loaded from files) by generative phantom types (first-class-polymorphism 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 | |
type 'y k = { k : 'n. 'n sized_list -> 'y } | |
(** This function has a type like | |
[forall 'y. string -> (forall 'n. 'n sized_list -> 'y) -> 'y]. *) | |
val load : string -> 'y k -> 'y | |
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 (+) | |
type 'y k = { k : 'n. 'n sized_list -> 'y } | |
let load fname {k} = k (load_list fname) | |
end | |
open SizedList | |
let () = | |
let k2 x1 x2 = (* k2 : 'n sized_type -> 'n sized_type -> unit | |
(k2 requires x1 and x2 have the same size.)*) | |
let w = add x1 x2 in | |
() | |
in | |
let k1 x1 = | |
let y = map (fun a -> a * 2) x1 in | |
let z = add x1 y in (* well-typed because x1 and y have the same length *) | |
load "file" { k = k2 x1 } (* ill-typed because (k2 x1) has | |
('n sized_list -> unit), but k requires | |
(forall 'n. 'n sized_list -> unit). *) | |
in | |
load "file" { k = k1 } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment