Part II (2016-11-29) Invited Talk VI @ CoAlpTy '16
Workshop on Coalgebra, Horn Clause Logic Programming and Types
Edinburgh, UK, 28–29 November 2016
Nanyang Technological University, Singapore
This slide is available online at https://slides.com/kyagrd/rowpoly-coalpty16
:- set_prolog_flag(occurs_check,true).
:- op(500,yfx,$).
type(C,var(X), T) :- first(X:T,C).
type(C,lam(X,E),A -> B) :- type([X:A|C], E, B).
type(C,E1 $ E2, B) :- type(C,E1,A->B),
type(C,E2,A).
first(K:V,[K1:V1|Xs]) :- K = K1, V = V1.
first(K:V,[K1:V1|Xs]) :- K\==K1, first(K:V, Xs).
:- set_prolog_flag(occurs_check,true).
:- op(500,yfx,$).
type(C,var(X), T) :- first(X:T,C).
type(C,lam(X,E),A -> B) :- type([X:A|C], E, B).
type(C,E1 $ E2, B) :- type(C,E1,A->B),
type(C,E2,A).
first(K:V,[K1:V1|Xs]) :- K = K1, V = V1.
first(K:V,[K1:V1|Xs]) :- K\==K1, first(K:V, Xs).
?- type([], lam(x,var(x)), A->A). % type checking true . ?- type([], lam(x,var(x)), T). % type inference T = (_G123->_G123) . ?- type([], E, A->A). % type inhabitation E = lam(_G234,var(_G234)) .
type(C,var(X), T1) :- first(X:T,C), inst(T,T1).
type(C,lam(X,E), A -> B) :- type([X:mono(A)|C],E,B).
type(C,E1 $ E2, B ) :- type(C,E1,A -> B),
type(C,E2,A).
type(C,let(X=E0,E1), T ) :- type(C,E0,A),
type([X:poly(C,A)|C],E1,T).
inst(mono(T),T).
inst(poly(C,T),T1) :- copy_term(t(C,T),t(C,T1)).
type(C,var(X), T1) :- first(X:T,C), inst(T,T1).
type(C,lam(X,E), A -> B) :- type([X:mono(A)|C],E,B).
type(C,E1 $ E2, B ) :- type(C,E1,A -> B), type(C,E2,A).
type(C,let(X=E0,E1), T ) :- type(C,E0,A),
type([X:poly(C,A)|C],E1,T).
inst(mono(T),T).
inst(poly(C,T),T1) :- copy_term(t(C,T),t(C,T1)).
?- copy_term(t([],A->B), t([],T)). T = (_G993->_G994). % fresh vars: _G993, _G994 for A, B ?- copy_term(t([x:A],A->B), t([x:A],T)). T = (A->_G1024). % fresh vars: _G1024 for B only
-- Tree :: (* -> *) -> * -> *
data Tree c a
= Leaf a -- Leaf :: Tree c a
| Node (c (Tree c a)) -- Node :: (c(Tree c a)) -> Tree c a
type BinTree a = Tree Pair a -- two children on each node
newtype Pair t = Pair (t,t)
type RoseTree a = Tree List a -- varying number of children
newtype List a = List [a]
HM only supports type polymorphism such as (1) but
not higher-kinded poly. such as (2) supported in Haskell
:- set_prolog_flag(occurs_check,true).
:- op(500,yfx,$).
first(K:V,[K1:V1|_]) :- K = K1, V = V1.
first(K:V,[K1:_|Zs]) :- K\==K1, first(K:V, Zs).
kind(KC,var(Z), K) :- first(Z:K,KC).
kind(KC,F $ G, K2) :- kind(KC,F,K1->K2), kind(KC,G,K1).
kind(KC,A -> B, o) :- kind(KC,A,o), kind(KC,B,o).
type(KC,C,var(X), A) --> { first(X:S,C) }, inst_ty(KC,S,A).
type(KC,C,lam(X,E),A->B) --> type(KC,[X:mono(A)|C],E,B),
[ kind(KC,A->B,o) ].
type(KC,C,E1 $ E2, B) --> type(KC,C,E1,A->B), type(KC,C,E2,A).
type(KC,C,let(X=E0,E),T) --> type(KC,C,E0,A),
type(KC,[X:poly(C,A)|C],E,T).
inst_ty(KC,poly(C,T),T2) --> { copy_term(t(C,T),t(C,T1)),
free_variables(T,Xs),
free_variables(T1,Xs1) },
samekinds(KC,Xs,Xs1), { T1=T2 }.
inst_ty(_, mono(T), T) --> [].
samekinds(KC,[X|Xs],[Y|Ys]) --> { X\==Y },
[ kind(KC,X,K), kind(KC,Y,K) ],
samekinds(KC,Xs,Ys).
samekinds(KC,[X|Xs],[X|Ys]) --> [], samekinds(KC,Xs,Ys).
samekinds(_ ,[], [] ) --> [].
variablize(var(X)) :- gensym(t,X).
main:-
process,
halt.
type_and_print(KC,C,E,T) :-
phrase(type(KC,C,E,T),Gs), print(success_type), nl,
(bagof(Ty, X^Y^member(kind(X,Ty,Y),Gs), Tys); Tys = []),
free_variables(Tys,Xs), maplist(variablize,Xs),
maplist(call,Gs),
write("kind ctx instantiated as: "), print(KC), nl, print(E : T), nl.
process:-
type_and_print(_,[],lam(x,var(x)),_), nl,
type_and_print(_,[],lam(x,lam(y,var(y)$var(x))),_), nl,
type_and_print(_,[],let(id=lam(x,var(x)),var(id)$var(id)),_), nl,
KC0 = [ 'Nat':o, 'List':(o->o) | _ ],
Nat = var('Nat'), List = var('List'),
C0 = [ 'Zero':mono(Nat)
, 'Succ':mono(Nat -> Nat)
, 'Nil' :poly([], List$A)
, 'Cons':poly([], A->((List$A)->(List$A))) ],
type_and_print(KC0,C0,lam(x,lam(n,var(x)$var('Succ')$var(n))),_),
true.
:- main.
type(KC,C,lam(X,E),A->B) --> type(KC,[X:mono(A)|C],E,B),
[ kind(KC,A->B,o) ].
type(KC, [], lam(x,var(x)), T)
--> {A->B/T}
type(KC,[x:mono(A)|[]],var(x),B), [ kind(KC,A->B,o) ]
--> ... --> {A/B}
type(KC,[x:mono(A)|[]),var(x),A), [ kind(KC,A->A,o) ]
% make logic var A into concrete var var(t1) befor kind infer
kind(KC, var(t1)->var(t1),o)
kind([t1:o|_], var(t1)->var(t1),o)
Ki Yung Ahn, Andrea Vezzosi: Executable Relational Specifications of Polymorphic Type Systems Using Prolog. FLOPS 2016: 109-125
Extensible Records without Subtyping
kind(KC,var(X), K1) :- first(X:K,KC).
kind(KC,F $ G, K2) :- K2\==row, kind(KC,F,K1->K2),
K1\==row, kind(KC,G,K1).
kind(KC,A -> B, o) :- kind(KC,A,o), kind(KC,B,o).
kind(KC,{R}, o) :- kind(KC,R,row).
kind(KC,[], row).
kind(KC,[X:T|R], row) :- kind(KC,T,o), kind(KC,R,row).
type(KC,C,var(X), A) --> { first(X:S,C) }, inst_ty(KC,S,A).
type(KC,C,lam(X,E),A->B) --> type(KC,[X:mono(A)|C],E,B),
[ kind(KC,A->B,o) ].
type(KC,C,X $ Y, B) --> type(KC,C,X,A->B), type(KC,C,Y,A1),
!, { eqty(A,A1) }. % note the cut !
type(KC,C,let(X=E0,E),T) --> type(KC,C,E0,A),
type(KC,[X:poly(C,A)|C],E,T).
type(KC,C,{XEs}, {R}) --> { zip_with('=',Xs,Es,XEs) },
type_many(KC,C,Es,Ts),
{ zip_with(':',Xs,Ts,R) }.
type(KC,C,sel(L,X), T) --> { first(X:T,R) }, type(KC,C,L,{R}).
type(KC,C,X $ Y, B) --> type(KC,C,X,A->B), type(KC,C,Y,A1),
!, { eqty(A,A1) }. % note the cut !
% more advanced notion of type equality at work
eqty(A1,A2) :- (var(A1); var(A2)), !, A1=A2.
eqty({R1},{R2}) :- !, unify_oemap(R1,R2). % like a permutation
eqty(A1->B1,A2->B2) :- !, eqty(A2,A1), !, eqty(B1,B2).
eqty(A,A).
% unify open ended maps (possibly variable tail at the end)
unify_oemap(A,B) :- ( var(A); var(B) ), !, A=B.
unify_oemap(A,B) :-
split_heads(A,Xs-T1), make_map(Xs,M1), % M1 is closed map
split_heads(B,Ys-T2), make_map(Ys,M2), % M2 is closed map
unify_oe_map(M1-T1, M2-T2). % calls eqty (mutual recursion)
generalization of open-ended set unification for maps and user defined equality