Skip to content

Commit 92eea24

Browse files
committed
unsound_unif, fmap and fset
1 parent edcf1f2 commit 92eea24

File tree

4 files changed

+532
-0
lines changed

4 files changed

+532
-0
lines changed

src/builtin.elpi

Lines changed: 264 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -462,6 +462,11 @@ external func same_term A, A.
462462
func (==) A, A.
463463
X == Y :- same_term X Y.
464464

465+
% Unification without occur check. It can create infinite terms.
466+
:nooc
467+
func unsound_unif -> A, A.
468+
unsound_unif X X.
469+
465470

466471
% [cmp_term A B Cmp] Compares A and B. Only works if A and B are ground.
467472
external func cmp_term any, any -> cmp.
@@ -1276,6 +1281,134 @@ bindings (node L V D R _) X X1 :-
12761281
} % std.map.private
12771282
} % std.map
12781283

1284+
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1285+
1286+
kind std.fmap type -> type -> type.
1287+
type std.fmap std.fmap.private.map K V -> (func K, K -> cmp) -> std.fmap K V.
1288+
1289+
namespace std.fmap {
1290+
1291+
% [make Eq Ltn M] builds an empty map M where keys are compared using Eq and Ltn
1292+
func make (func K, K -> cmp) -> std.fmap K V.
1293+
make Cmp (std.fmap private.empty Cmp).
1294+
1295+
% [find K M V] looks in M for the value V associated to K
1296+
func find K, std.fmap K V -> V.
1297+
find K (std.fmap M Cmp) V :-
1298+
private.assert-ground K,
1299+
private.find M Cmp K V.
1300+
1301+
% [add K V M M1] M1 is M where K is bound to V
1302+
func add K, V, std.fmap K V -> std.fmap K V.
1303+
add K V (std.fmap M Cmp) R :-
1304+
private.assert-ground K,
1305+
private.assert-ground V,
1306+
private.add M Cmp K V M1,
1307+
unsound_unif R (std.fmap M1 Cmp).
1308+
1309+
% [remove K M M1] M1 is M where K is unbound
1310+
func remove K, std.fmap K V -> std.fmap K V.
1311+
remove K (std.fmap M Cmp) R :-
1312+
private.assert-ground K,
1313+
private.remove M Cmp K M1,
1314+
unsound_unif R (std.fmap M1 Cmp).
1315+
1316+
% [bindings M L] L is the key-value pairs in increasing order
1317+
func bindings std.fmap K V -> list (pair K V).
1318+
bindings (std.fmap M _) L :- private.bindings M [] L.
1319+
1320+
namespace private {
1321+
1322+
func assert-ground A.
1323+
assert-ground A :- std.assert! (ground_term A) "std.fmap: not ground".
1324+
1325+
% Taken from OCaml's map.ml
1326+
kind map type -> type -> type.
1327+
type empty map K V.
1328+
type node map K V -> K -> V -> map K V -> int -> map K V.
1329+
1330+
func height map K V -> int.
1331+
height empty 0.
1332+
height (node _ _ _ _ H) H.
1333+
1334+
func create map K V, K, V, map K V -> map K V.
1335+
create L K V R X :-
1336+
H is {std.max {height L} {height R}} + 1,
1337+
unsound_unif X (node L K V R H).
1338+
1339+
func bal map K V, K, V, map K V -> map K V.
1340+
bal L K V R T :-
1341+
height L HL,
1342+
height R HR,
1343+
HL2 is HL + 2,
1344+
HR2 is HR + 2,
1345+
bal.aux HL HR HL2 HR2 L K V R T.
1346+
1347+
func bal.aux int, int, int, int, map K V, K, V, map K V -> map K V.
1348+
bal.aux HL _ _ HR2 (node LL LV LD LR _) X D R T :-
1349+
HL > HR2, {height LL} >= {height LR}, !,
1350+
create LL LV LD {create LR X D R} T.
1351+
bal.aux HL _ _ HR2 (node LL LV LD (node LRL LRV LRD LRR _) _) X D R T :-
1352+
HL > HR2, !,
1353+
create {create LL LV LD LRL} LRV LRD {create LRR X D R} T.
1354+
bal.aux _ HR HL2 _ L X D (node RL RV RD RR _) T :-
1355+
HR > HL2, {height RR} >= {height RL}, !,
1356+
create {create L X D RL} RV RD RR T.
1357+
bal.aux _ HR HL2 _ L X D (node (node RLL RLV RLD RLR _) RV RD RR _) T :-
1358+
HR > HL2, !,
1359+
create {create L X D RLL} RLV RLD {create RLR RV RD RR} T.
1360+
bal.aux _ _ _ _ L K V R T :- create L K V R T.
1361+
1362+
func add map K V, (func K, K -> cmp), K, V -> map K V.
1363+
add empty _ K V T :- create empty K V empty T.
1364+
add (node _ X _ _ _ as M) Cmp X1 XD M1 :- Cmp X1 X E, add.aux E M Cmp X1 XD M1.
1365+
1366+
func add.aux cmp, map K V, (func K, K -> cmp), K, V -> map K V.
1367+
add.aux eq (node L _ _ R H) _ X XD T :- unsound_unif T (node L X XD R H).
1368+
add.aux lt (node L V D R _) Cmp X XD T :- bal {add L Cmp X XD} V D R T.
1369+
add.aux gt (node L V D R _) Cmp X XD T :- bal L V D {add R Cmp X XD} T.
1370+
1371+
func find map K V, (func K, K -> cmp), K -> V.
1372+
find (node L K1 V1 R _) Cmp K V :- Cmp K K1 E, find.aux E Cmp L R V1 K V.
1373+
1374+
func find.aux cmp, (func K, K -> cmp), map K V, map K V, V, K -> V.
1375+
find.aux eq _ _ _ V _ V.
1376+
find.aux lt Cmp L _ _ K V :- find L Cmp K V.
1377+
find.aux gt Cmp _ R _ K V :- find R Cmp K V.
1378+
1379+
func remove-min-binding map K V -> map K V.
1380+
remove-min-binding (node empty _ _ R _) R :- !.
1381+
remove-min-binding (node L V D R _) X :- bal {remove-min-binding L} V D R X.
1382+
1383+
func min-binding map K V -> K, V.
1384+
min-binding (node empty V D _ _) V D :- !.
1385+
min-binding (node L _ _ _ _) V D :- min-binding L V D.
1386+
1387+
func merge map K V, map K V -> map K V.
1388+
merge empty X X :- !.
1389+
merge X empty X :- !.
1390+
merge M1 M2 R :-
1391+
min-binding M2 X D,
1392+
bal M1 X D {remove-min-binding M2} R.
1393+
1394+
func remove map K V, (func K, K -> cmp), K -> map K V.
1395+
remove empty _ _ empty :- !.
1396+
remove (node L V D R _) Cmp X M :- Cmp X V E, remove.aux E Cmp L R V D X M.
1397+
1398+
func remove.aux cmp, (func K, K -> cmp), map K V, map K V, K, V, K -> map K V.
1399+
remove.aux eq _ L R _ _ _ M :- merge L R M.
1400+
remove.aux lt Cmp L R V D X M :- bal {remove L Cmp X} V D R M.
1401+
remove.aux gt Cmp L R V D X M :- bal L V D {remove R Cmp X} M.
1402+
1403+
func bindings map K V, list (pair K V) -> list (pair K V).
1404+
bindings empty X X.
1405+
bindings (node L V D R _) X X1 :-
1406+
bindings L [pr V D|{bindings R X}] X1.
1407+
1408+
1409+
} % std.fmap.private
1410+
} % std.fmap
1411+
12791412

12801413
#line 1 "builtin_set.elpi"
12811414
kind std.set type -> type.
@@ -1396,6 +1529,137 @@ elements (node L E R _) Acc X :-
13961529
} % std.set.private
13971530
} % std.set
13981531

1532+
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1533+
1534+
kind std.fset type -> type.
1535+
type std.fset std.fset.private.set E -> (func E, E -> cmp) -> std.fset E.
1536+
1537+
namespace std.fset {
1538+
1539+
% [make Eq Ltn M] builds an empty set M where keys are compared using Eq and Ltn
1540+
func make (func E, E -> cmp) -> std.fset E.
1541+
make Cmp (std.fset private.empty Cmp).
1542+
1543+
% [mem E M] looks if E is in M
1544+
func mem E, std.fset E.
1545+
mem E (std.fset M Cmp):- private.mem M Cmp E.
1546+
1547+
% [add E M M1] M1 is M + {E}
1548+
func add E, std.fset E -> std.fset E.
1549+
add E (std.fset M Cmp) R :-
1550+
private.assert-ground E,
1551+
private.add M Cmp E M1,
1552+
unsound_unif R (std.fset M1 Cmp).
1553+
1554+
% [remove E M M1] M1 is M - {E}
1555+
func remove E, std.fset E -> std.fset E.
1556+
remove E (std.fset M Cmp) R :-
1557+
private.assert-ground E,
1558+
private.remove M Cmp E M1,
1559+
unsound_unif R (std.fset M1 Cmp).
1560+
1561+
% [cardinal S N] N is the number of elements of S
1562+
func cardinal std.fset E -> int.
1563+
cardinal (std.fset M _) N :- private.cardinal M N.
1564+
1565+
func elements std.fset E -> list E.
1566+
elements (std.fset M _) L :- private.elements M [] L.
1567+
1568+
namespace private {
1569+
1570+
func assert-ground A.
1571+
assert-ground A :- std.assert! (ground_term A) "std.fset: not ground".
1572+
1573+
% Taken from OCaml's set.ml
1574+
kind set type -> type.
1575+
type empty set E.
1576+
type node set E -> E -> set E -> int -> set E.
1577+
1578+
func height set E -> int.
1579+
height empty 0.
1580+
height (node _ _ _ H) H.
1581+
1582+
func create set E, E, set E -> set E.
1583+
create L E R S :-
1584+
H is {std.max {height L} {height R}} + 1,
1585+
unsound_unif S (node L E R H).
1586+
1587+
func bal set E, E, set E -> set E.
1588+
bal L E R T :-
1589+
height L HL,
1590+
height R HR,
1591+
HL2 is HL + 2,
1592+
HR2 is HR + 2,
1593+
bal.aux HL HR HL2 HR2 L E R T.
1594+
1595+
func bal.aux int, int, int, int, set E, E, set E -> set E.
1596+
bal.aux HL _ _ HR2 (node LL LV LR _) X R T :-
1597+
HL > HR2, {height LL} >= {height LR}, !,
1598+
create LL LV {create LR X R} T.
1599+
bal.aux HL _ _ HR2 (node LL LV (node LRL LRV LRR _) _) X R T :-
1600+
HL > HR2, !,
1601+
create {create LL LV LRL} LRV {create LRR X R} T.
1602+
bal.aux _ HR HL2 _ L X (node RL RV RR _) T :-
1603+
HR > HL2, {height RR} >= {height RL}, !,
1604+
create {create L X RL} RV RR T.
1605+
bal.aux _ HR HL2 _ L X (node (node RLL RLV RLR _) RV RR _) T :-
1606+
HR > HL2, !,
1607+
create {create L X RLL} RLV {create RLR RV RR} T.
1608+
bal.aux _ _ _ _ L E R T :- create L E R T.
1609+
1610+
func add set E, (func E, E -> cmp), E -> set E.
1611+
add empty _ E T :- create empty E empty T.
1612+
add (node L X R H) Cmp X1 S :- Cmp X1 X E, add.aux E Cmp L R X X1 H S.
1613+
1614+
func add.aux cmp, (func E, E -> cmp), set E, set E, E, E, int -> set E.
1615+
add.aux eq _ L R X _ H S :- unsound_unif S (node L X R H).
1616+
add.aux lt Cmp L R E X _ T :- bal {add L Cmp X} E R T.
1617+
add.aux gt Cmp L R E X _ T :- bal L E {add R Cmp X} T.
1618+
1619+
func mem set E, (func E, E -> cmp), E.
1620+
mem (node L K R _) Cmp E :- Cmp E K O, mem.aux O Cmp L R E.
1621+
1622+
func mem.aux cmp, (func E, E -> cmp), set E, set E, E.
1623+
mem.aux eq _ _ _ _.
1624+
mem.aux lt Cmp L _ E :- mem L Cmp E.
1625+
mem.aux gt Cmp _ R E :- mem R Cmp E.
1626+
1627+
func remove-min-binding set E -> set E.
1628+
remove-min-binding (node empty _ R _) R :- !.
1629+
remove-min-binding (node L E R _) X :- bal {remove-min-binding L} E R X.
1630+
1631+
func min-binding set E -> E.
1632+
min-binding (node empty E _ _) E :- !.
1633+
min-binding (node L _ _ _) E :- min-binding L E.
1634+
1635+
func merge set E, set E -> set E.
1636+
merge empty X X :- !.
1637+
merge X empty X :- !.
1638+
merge M1 M2 R :-
1639+
min-binding M2 X,
1640+
bal M1 X {remove-min-binding M2} R.
1641+
1642+
func remove set E, (func E, E -> cmp), E -> set E.
1643+
remove empty _ _ empty.
1644+
remove (node L E R _) Cmp X M :- Cmp X E O, remove.aux O Cmp L R E X M.
1645+
1646+
func remove.aux cmp, (func E, E -> cmp), set E, set E, E, E -> set E.
1647+
remove.aux eq _ L R _ _ M :- merge L R M.
1648+
remove.aux lt Cmp L R E X M :- bal {remove L Cmp X} E R M.
1649+
remove.aux gt Cmp L R E X M :- bal L E {remove R Cmp X} M.
1650+
1651+
func cardinal set E -> int.
1652+
cardinal empty 0.
1653+
cardinal (node L _ R _) N :- N is {cardinal L} + 1 + {cardinal R}.
1654+
1655+
func elements set E, list E -> list E.
1656+
elements empty X X.
1657+
elements (node L E R _) Acc X :-
1658+
elements L [E|{elements R Acc}] X.
1659+
1660+
} % std.fset.private
1661+
} % std.fset
1662+
13991663

14001664
% == Elpi runtime builtins =====================================
14011665

src/builtin.ml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -851,6 +851,11 @@ let elpi_nonlogical_builtins = let open BuiltIn in let open BuiltInData in let o
851851
% Infix notation for same_term
852852
func (==) A, A.
853853
X == Y :- same_term X Y.
854+
855+
% Unification without occur check. It can create infinite terms.
856+
:nooc
857+
func unsound_unif -> A, A.
858+
unsound_unif X X.
854859
|};
855860

856861
MLCode(Pred("cmp_term",

0 commit comments

Comments
 (0)