Mercurial > urweb
changeset 82:b4f2a258e52c
Initial disjointness prover
author | Adam Chlipala <adamc@hcoop.net> |
---|---|
date | Tue, 01 Jul 2008 10:55:38 -0400 |
parents | 60d97de1bbe8 |
children | 0a1baddd8ab2 |
files | src/disjoint.sig src/disjoint.sml src/elab.sml src/elab_print.sml src/elab_util.sml src/elaborate.sml src/explify.sml src/lacweb.grm src/lacweb.lex src/source.sml src/source_print.sml src/sources tests/disjoint.lac |
diffstat | 13 files changed, 374 insertions(+), 1 deletions(-) [+] |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/disjoint.sig Tue Jul 01 10:55:38 2008 -0400 @@ -0,0 +1,38 @@ +(* Copyright (c) 2008, Adam Chlipala + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * - The names of contributors may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + *) + +signature DISJOINT = sig + + type env + + val empty : env + val assert : ElabEnv.env -> env -> Elab.con * Elab.con -> env + val enter : env -> env + + val prove : ElabEnv.env -> env -> Elab.con * Elab.con * ErrorMsg.span -> (Elab.con * Elab.con) list + +end
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/disjoint.sml Tue Jul 01 10:55:38 2008 -0400 @@ -0,0 +1,294 @@ +(* Copyright (c) 2008, Adam Chlipala + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * - The names of contributors may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + *) + +structure Disjoint :> DISJOINT = struct + +open Elab +open ElabOps + +structure SS = BinarySetFn(struct + type ord_key = string + val compare = String.compare + end) + +structure IS = IntBinarySet +structure IM = IntBinaryMap + +type name_ineqs = { + namesC : SS.set, + namesR : IS.set, + namesN : IS.set +} + +val name_default = { + namesC = SS.empty, + namesR = IS.empty, + namesN = IS.empty +} + +type row_ineqs = { + namesC : SS.set, + namesR : IS.set, + namesN : IS.set, + rowsR : IS.set, + rowsN : IS.set +} + +val row_default = { + namesC = SS.empty, + namesR = IS.empty, + namesN = IS.empty, + rowsR = IS.empty, + rowsN = IS.empty +} + +fun nameToRow_ineqs {namesC, namesR, namesN} = + {namesC = namesC, + namesR = namesR, + namesN = namesN, + rowsR = IS.empty, + rowsN = IS.empty} + +type env = { + namesR : name_ineqs IM.map, + namesN : name_ineqs IM.map, + rowsR : row_ineqs IM.map, + rowsN : row_ineqs IM.map +} + +val empty = { + namesR = IM.empty, + namesN = IM.empty, + rowsR = IM.empty, + rowsN = IM.empty +} + +datatype piece = + NameC of string + | NameR of int + | NameN of int + | RowR of int + | RowN of int + | Unknown + +fun nameToRow (c, loc) = + (CRecord ((KUnit, loc), [((c, loc), (CUnit, loc))]), loc) + +fun pieceToRow (p, loc) = + case p of + NameC s => nameToRow (CName s, loc) + | NameR n => nameToRow (CRel n, loc) + | NameN n => nameToRow (CNamed n, loc) + | RowR n => (CRel n, loc) + | RowN n => (CRel n, loc) + | Unknown => raise Fail "Unknown to row" + +fun decomposeRow env c = + let + fun decomposeName (c, acc) = + case #1 (hnormCon env c) of + CName s => NameC s :: acc + | CRel n => NameR n :: acc + | CNamed n => NameN n :: acc + | _ => Unknown :: acc + + fun decomposeRow (c, acc) = + case #1 (hnormCon env c) of + CRecord (_, xcs) => foldl (fn ((x, _), acc) => decomposeName (x, acc)) acc xcs + | CConcat (c1, c2) => decomposeRow (c1, decomposeRow (c2, acc)) + | CRel n => RowR n :: acc + | CNamed n => RowN n :: acc + | _ => Unknown :: acc + in + decomposeRow (c, []) + end + +fun assertPiece_name (ps, ineqs : name_ineqs) = + {namesC = foldl (fn (p', namesC) => + case p' of + NameC s => SS.add (namesC, s) + | _ => namesC) (#namesC ineqs) ps, + namesR = foldl (fn (p', namesR) => + case p' of + NameR n => IS.add (namesR, n) + | _ => namesR) (#namesR ineqs) ps, + namesN = foldl (fn (p', namesN) => + case p' of + NameN n => IS.add (namesN, n) + | _ => namesN) (#namesN ineqs) ps} + +fun assertPiece_row (ps, ineqs : row_ineqs) = + {namesC = foldl (fn (p', namesC) => + case p' of + NameC s => SS.add (namesC, s) + | _ => namesC) (#namesC ineqs) ps, + namesR = foldl (fn (p', namesR) => + case p' of + NameR n => IS.add (namesR, n) + | _ => namesR) (#namesR ineqs) ps, + namesN = foldl (fn (p', namesN) => + case p' of + NameN n => IS.add (namesN, n) + | _ => namesN) (#namesN ineqs) ps, + rowsR = foldl (fn (p', rowsR) => + case p' of + RowR n => IS.add (rowsR, n) + | _ => rowsR) (#rowsR ineqs) ps, + rowsN = foldl (fn (p', rowsN) => + case p' of + RowN n => IS.add (rowsN, n) + | _ => rowsN) (#rowsN ineqs) ps} + +fun assertPiece ps (p, denv) = + case p of + Unknown => denv + | NameC _ => denv + + | NameR n => + let + val ineqs = Option.getOpt (IM.find (#namesR denv, n), name_default) + val ineqs = assertPiece_name (ps, ineqs) + in + {namesR = IM.insert (#namesR denv, n, ineqs), + namesN = #namesN denv, + rowsR = #rowsR denv, + rowsN = #rowsN denv} + end + + | NameN n => + let + val ineqs = Option.getOpt (IM.find (#namesN denv, n), name_default) + val ineqs = assertPiece_name (ps, ineqs) + in + {namesR = #namesR denv, + namesN = IM.insert (#namesN denv, n, ineqs), + rowsR = #rowsR denv, + rowsN = #rowsN denv} + end + + | RowR n => + let + val ineqs = Option.getOpt (IM.find (#rowsR denv, n), row_default) + val ineqs = assertPiece_row (ps, ineqs) + in + {namesR = #namesR denv, + namesN = #namesN denv, + rowsR = IM.insert (#rowsR denv, n, ineqs), + rowsN = #rowsN denv} + end + + | RowN n => + let + val ineqs = Option.getOpt (IM.find (#rowsN denv, n), row_default) + val ineqs = assertPiece_row (ps, ineqs) + in + {namesR = #namesR denv, + namesN = #namesN denv, + rowsR = #rowsR denv, + rowsN = IM.insert (#rowsN denv, n, ineqs)} + end + +fun assert env denv (c1, c2) = + let + val ps1 = decomposeRow env c1 + val ps2 = decomposeRow env c2 + + val denv = foldl (assertPiece ps2) denv ps1 + in + foldl (assertPiece ps1) denv ps2 + end + +fun nameEnter {namesC, namesR, namesN} = + {namesC = namesC, + namesR = IS.map (fn n => n + 1) namesR, + namesN = namesN} + +fun rowEnter {namesC, namesR, namesN, rowsR, rowsN} = + {namesC = namesC, + namesR = IS.map (fn n => n + 1) namesR, + namesN = namesN, + rowsR = IS.map (fn n => n + 1) rowsR, + rowsN = rowsN} + +fun enter {namesR, namesN, rowsR, rowsN} = + {namesR = IM.foldli (fn (n, ineqs, namesR) => IM.insert (namesR, n+1, nameEnter ineqs)) IM.empty namesR, + namesN = IM.map nameEnter namesN, + rowsR = IM.foldli (fn (n, ineqs, rowsR) => IM.insert (rowsR, n+1, rowEnter ineqs)) IM.empty rowsR, + rowsN = IM.map rowEnter rowsN} + +fun getIneqs (denv : env) p = + case p of + Unknown => raise Fail "getIneqs: Unknown" + | NameC _ => raise Fail "getIneqs: NameC" + | NameR n => nameToRow_ineqs (Option.getOpt (IM.find (#namesR denv, n), name_default)) + | NameN n => nameToRow_ineqs (Option.getOpt (IM.find (#namesN denv, n), name_default)) + | RowR n => Option.getOpt (IM.find (#rowsR denv, n), row_default) + | RowN n => Option.getOpt (IM.find (#rowsN denv, n), row_default) + +fun prove1' denv (p1, p2) = + let + val {namesC, namesR, namesN, rowsR, rowsN} = getIneqs denv p1 + in + case p2 of + Unknown => raise Fail "prove1': Unknown" + | NameC s => SS.member (namesC, s) + | NameR n => IS.member (namesR, n) + | NameN n => IS.member (namesN, n) + | RowR n => IS.member (rowsR, n) + | RowN n => IS.member (rowsN, n) + end + +fun prove1 denv (p1, p2) = + case (p1, p2) of + (NameC s1, NameC s2) => s1 <> s2 + | (_, RowR _) => prove1' denv (p2, p1) + | (_, RowN _) => prove1' denv (p2, p1) + | _ => prove1' denv (p1, p2) + +fun prove env denv (c1, c2, loc) = + let + val ps1 = decomposeRow env c1 + val ps2 = decomposeRow env c2 + + val hasUnknown = List.exists (fn p => p = Unknown) + in + if hasUnknown ps1 orelse hasUnknown ps2 then + (ErrorMsg.errorAt loc "Structure of row is too complicated to prove disjointness"; + Print.eprefaces' [("Row 1", ElabPrint.p_con env c1), + ("Row 2", ElabPrint.p_con env c2)]; + []) + else + foldl (fn (p1, rem) => + foldl (fn (p2, rem) => + if prove1 denv (p1, p2) then + rem + else + (pieceToRow (p1, loc), pieceToRow (p2, loc)) :: rem) rem ps2) + [] ps1 + end + +end
--- a/src/elab.sml Tue Jul 01 09:29:49 2008 -0400 +++ b/src/elab.sml Tue Jul 01 10:55:38 2008 -0400 @@ -34,6 +34,7 @@ | KArrow of kind * kind | KName | KRecord of kind + | KUnit | KError | KUnif of ErrorMsg.span * string * kind option ref @@ -61,6 +62,8 @@ | CConcat of con * con | CFold of kind * kind + | CUnit + | CError | CUnif of ErrorMsg.span * kind * string * con option ref
--- a/src/elab_print.sml Tue Jul 01 09:29:49 2008 -0400 +++ b/src/elab_print.sml Tue Jul 01 10:55:38 2008 -0400 @@ -48,6 +48,7 @@ p_kind k2]) | KName => string "Name" | KRecord k => box [string "{", p_kind k, string "}"] + | KUnit => string "Unit" | KError => string "<ERROR>" | KUnif (_, _, ref (SOME k)) => p_kind' par k @@ -155,6 +156,8 @@ p_con env c2]) | CFold _ => string "fold" + | CUnit => string "()" + | CError => string "<ERROR>" | CUnif (_, _, _, ref (SOME c)) => p_con' par env c | CUnif (_, k, s, _) => box [string ("<UNIF:" ^ s ^ "::"),
--- a/src/elab_util.sml Tue Jul 01 09:29:49 2008 -0400 +++ b/src/elab_util.sml Tue Jul 01 10:55:38 2008 -0400 @@ -56,6 +56,8 @@ fn k' => (KRecord k', loc)) + | KUnit => S.return2 kAll + | KError => S.return2 kAll | KUnif (_, _, ref (SOME k)) => mfk' k @@ -150,6 +152,8 @@ fn k2' => (CFold (k1', k2'), loc))) + | CUnit => S.return2 cAll + | CError => S.return2 cAll | CUnif (_, _, _, ref (SOME c)) => mfc' ctx c | CUnif _ => S.return2 cAll
--- a/src/elaborate.sml Tue Jul 01 09:29:49 2008 -0400 +++ b/src/elaborate.sml Tue Jul 01 10:55:38 2008 -0400 @@ -32,6 +32,7 @@ structure L' = Elab structure E = ElabEnv structure U = ElabUtil +structure D = Disjoint open Print open ElabPrint @@ -73,6 +74,8 @@ in case (k1, k2) of (L'.KType, L'.KType) => () + | (L'.KUnit, L'.KUnit) => () + | (L'.KArrow (d1, r1), L'.KArrow (d2, r2)) => (unifyKinds' d1 d2; unifyKinds' r1 r2) @@ -199,6 +202,7 @@ | L.KArrow (k1, k2) => (L'.KArrow (elabKind k1, elabKind k2), loc) | L.KName => (L'.KName, loc) | L.KRecord k => (L'.KRecord (elabKind k), loc) + | L.KUnit => (L'.KUnit, loc) | L.KWild => kunif loc fun foldKind (dom, ran, loc)= @@ -330,6 +334,10 @@ val ku = kunif loc val k = (L'.KRecord ku, loc) in + case D.prove env D.empty (c1', c2', loc) of + [] => () + | _ => raise Fail "Can't prove disjointness"; + checkKind env c1' k1 k; checkKind env c2' k2 k; ((L'.CConcat (c1', c2'), loc), k) @@ -343,6 +351,8 @@ foldKind (dom, ran, loc)) end + | L.CUnit => ((L'.CUnit, loc), (L'.KUnit, loc)) + | L.CWild k => let val k' = elabKind k @@ -478,6 +488,8 @@ | L'.CConcat (c, _) => kindof env c | L'.CFold (dom, ran) => foldKind (dom, ran, loc) + | L'.CUnit => (L'.KUnit, loc) + | L'.CError => kerror | L'.CUnif (_, k, _, _) => k
--- a/src/explify.sml Tue Jul 01 09:29:49 2008 -0400 +++ b/src/explify.sml Tue Jul 01 10:55:38 2008 -0400 @@ -38,6 +38,8 @@ | L.KName => (L'.KName, loc) | L.KRecord k => (L'.KRecord (explifyKind k), loc) + | L.KUnit => raise Fail "Explify KUnit" + | L.KError => raise Fail ("explifyKind: KError at " ^ EM.spanToString loc) | L.KUnif (_, _, ref (SOME k)) => explifyKind k | L.KUnif _ => raise Fail ("explifyKind: KUnif at " ^ EM.spanToString loc) @@ -61,6 +63,8 @@ | L.CConcat (c1, c2) => (L'.CConcat (explifyCon c1, explifyCon c2), loc) | L.CFold (dom, ran) => (L'.CFold (explifyKind dom, explifyKind ran), loc) + | L.CUnit => raise Fail "Explify CUnit" + | L.CError => raise Fail ("explifyCon: CError at " ^ EM.spanToString loc) | L.CUnif (_, _, _, ref (SOME c)) => explifyCon c | L.CUnif _ => raise Fail ("explifyCon: CUnif at " ^ EM.spanToString loc)
--- a/src/lacweb.grm Tue Jul 01 09:29:49 2008 -0400 +++ b/src/lacweb.grm Tue Jul 01 10:55:38 2008 -0400 @@ -40,7 +40,7 @@ | SYMBOL of string | CSYMBOL of string | LPAREN | RPAREN | LBRACK | RBRACK | LBRACE | RBRACE | EQ | COMMA | COLON | DCOLON | TCOLON | DOT | HASH | UNDER | UNDERUNDER - | CON | LTYPE | VAL | FOLD + | CON | LTYPE | VAL | FOLD | UNIT | KUNIT | TYPE | NAME | ARROW | LARROW | DARROW | FN | PLUSPLUS | DOLLAR @@ -179,6 +179,7 @@ | LBRACE kind RBRACE (KRecord kind, s (LBRACEleft, RBRACEright)) | kind ARROW kind (KArrow (kind1, kind2), s (kind1left, kind2right)) | LPAREN kind RPAREN (#1 kind, s (LPARENleft, RPARENright)) + | KUNIT (KUnit, s (KUNITleft, KUNITright)) | UNDERUNDER (KWild, s (UNDERUNDERleft, UNDERUNDERright)) capps : cterm (cterm) @@ -216,6 +217,7 @@ | path (CVar path, s (pathleft, pathright)) | UNDER (CWild (KWild, s (UNDERleft, UNDERright)), s (UNDERleft, UNDERright)) | FOLD (CFold, s (FOLDleft, FOLDright)) + | UNIT (CUnit, s (UNITleft, UNITright)) rcon : ([]) | ident EQ cexp ([(ident, cexp)])
--- a/src/lacweb.lex Tue Jul 01 09:29:49 2008 -0400 +++ b/src/lacweb.lex Tue Jul 01 10:55:38 2008 -0400 @@ -120,6 +120,7 @@ str := #"\n" :: !str; continue()); <STRING> . => (str := String.sub (yytext, 0) :: !str; continue()); +<INITIAL> "()" => (Tokens.UNIT (pos yypos, pos yypos + size yytext)); <INITIAL> "(" => (Tokens.LPAREN (pos yypos, pos yypos + size yytext)); <INITIAL> ")" => (Tokens.RPAREN (pos yypos, pos yypos + size yytext)); <INITIAL> "[" => (Tokens.LBRACK (pos yypos, pos yypos + size yytext)); @@ -161,6 +162,7 @@ <INITIAL> "Type" => (Tokens.TYPE (pos yypos, pos yypos + size yytext)); <INITIAL> "Name" => (Tokens.NAME (pos yypos, pos yypos + size yytext)); +<INITIAL> "Unit" => (Tokens.KUNIT (pos yypos, pos yypos + size yytext)); <INITIAL> {id} => (Tokens.SYMBOL (yytext, pos yypos, pos yypos + size yytext)); <INITIAL> {cid} => (Tokens.CSYMBOL (yytext, pos yypos, pos yypos + size yytext));
--- a/src/source.sml Tue Jul 01 09:29:49 2008 -0400 +++ b/src/source.sml Tue Jul 01 10:55:38 2008 -0400 @@ -34,6 +34,7 @@ | KArrow of kind * kind | KName | KRecord of kind + | KUnit | KWild withtype kind = kind' located @@ -59,6 +60,8 @@ | CConcat of con * con | CFold + | CUnit + | CWild of kind withtype con = con' located
--- a/src/source_print.sml Tue Jul 01 09:29:49 2008 -0400 +++ b/src/source_print.sml Tue Jul 01 10:55:38 2008 -0400 @@ -44,6 +44,7 @@ p_kind k2]) | KName => string "Name" | KRecord k => box [string "{", p_kind k, string "}"] + | KUnit => string "Unit" | KWild => string "_" and p_kind k = p_kind' false k @@ -127,6 +128,9 @@ space, p_con c2]) | CFold => string "fold" + + | CUnit => string "()" + | CWild k => box [string "(_", space, string "::",