Skip to content

Instantly share code, notes, and snippets.

@hsk
Last active October 11, 2016 05:47
Show Gist options
  • Save hsk/ce4668cdaf05b6e95005dc142591870e to your computer and use it in GitHub Desktop.
Save hsk/ce4668cdaf05b6e95005dc142591870e to your computer and use it in GitHub Desktop.
Evaluation contexts
/*
構文
x, y, z 変数
v ::= 値
 λ(x:T)t ラムダ
s, t, u ::= 項
 x 変数
 v 値
 x y 関数適用
 let x = t in u let式
評価規則 t ---> t
let x = v in e[x y] ---> let x = v in e[[z := y]t] if v=λ(z:T)t
let x = y in t ---> [x::=y] t
let x = let y = s in t in u ---> let y = s in let x = t in u
e[t] ---> e[u] if t ---> u
where e::=[] | let x = [] in t | let x = v in e
*/
:- initialization(main).
:- op(920, xfx, [ --->, -->> ]).
:- op(500, yfx, $).
v(X->_) :- atom(X).
% 答
a(V,V) :- v(V).
a(X,X) :- atom(X).
a(let(X=V,A),V) :- a(A,X).
a(let(_=_,A),A_) :- a(A,A_).
% 文脈、パラメータ取得
e(let(X=U,T),let(X=[],T),U):- \+v(U).
e(let(X=V,E),let(X=V,E_),H):- v(V), e(E,E_,H).
e(T,[],T).
subst(S,S_,S,S_).
subst(S,S_,X->T,X->T_) :- S \= X, subst(S,S_,T,T_).
subst(S,S_,T$U,T_$U_) :- subst(S,S_,T,T_), subst(S,S_,U,U_).
subst(S,S_,let(X=T,U),let(X=T_,U_)) :- S\=X,subst(S,S_,T,T_), subst(S,S_,U,U_).
subst(_,_,T,T).
let(X=V,EXV) ---> let(X=V,ET_) :- e(EXV,E,(X$Y)), V=(Z->T), subst(Z,Y,T,T_), subst([],T_,E,ET_).
let(X=Y,T) ---> T_ :- atom(Y), subst(X,Y,T,T_).
let(X=let(Y=S,T),U) ---> let(Y=S,let(X=T,U)).
T ---> T_ :- e(T,EC,U), T \= U, U ---> U_, subst([],U_,EC,T_).
% 複数ステップ実行
T -->> T_ :- writeln(T),T--->U,!,U-->>T_.
T -->> T_ :- a(T,T_),(T=T_;writeln(T_)),nl.
:- (x->x)-->>R,R=(x->x).
:- let(yy=(y->y),yy)-->>R,R=(y->y).
:- let(xx=(x->x),let(yy=(y->y),xx$yy))-->>R,R=(y->y).
:- let(xx=(x->x),let(yy=(y->y),let(zz=(z->z),let(yyzz=yy$zz,xx$yyzz))))-->>R,R=(z->z).
:- halt.
/*
構文
x, y, z 変数
v ::= 値
 λ(x)t ラムダ
s, t, u ::= 項
 x 変数
 v 値
 x y 関数適用
 let x = t in u let式
(Apply)
s | x y --> s | [z:=s(y)]t if s(x) = lambda(z: T)t
(Let-Var)
s | let x = y in t --> s | [x:=s(y)]t
(Let-Value)
s | let x = v in t --> s, x = v | t
(Ctx)
s | t --> s' | t'
------------------------------------
let x = t in u --> let x = t' in u
*/
% 値
v(lam(X,_)) :- atom(X).
% 答
a(lam(X,T),lam(X,T)).
a(let(_,_,A),A_) :- a(A,A_).
% 置換
subst(X,T,X,T).
subst(X,T,lam(X1,T1),lam(X1,T1_)) :- subst(X,T,T1,T1_), X \=X1.
subst(X,T,app(T1,T2),app(T1_,T2_)) :- subst(X,T,T1,T1_), subst(X,T,T2,T2_).
subst(X,T,let(X1,T1,T2),let(X1,T1_,T2_)) :- subst(X,T,T1,T1_), subst(X,T,T2,T2_), X\=X1.
subst(_,_,E,E).
% ワンステップ実行
eval1(S,app(X,Y), S,T_) :- member(X=lam(Z,T),S),member(Y=V,S),subst(Z,V,T,T_). % (Apply)
eval1(S,let(X,Y,T),S,T_):- member(Y=V,S),subst(X,V,T,T_). % (Let-Var)
eval1(S,let(X,V,T),[X=V|S],T) :- v(V). % (Let-Value)
eval1(S,let(X,T,U),S_,let(X,T_,U)) :- eval1(S,T,S_,T_). % (Ctx)
% 複数ステップ実行
eval(S,T,S_,T_) :- writeln(T),eval1(S,T,S1,T1),!,eval(S1,T1,S_,T_).
eval(S,T,S,T) :- nl.
eval(T,T_) :- eval([],T,_,T1), a(T1,T_).
:- eval(lam(x,x),R),R=lam(x,x).
:- eval(let(xx,lam(x,x),let(yy,lam(y,y),app(xx,yy))),R),R=lam(y,y).
:- eval(let(xx,lam(x,x),let(yy,lam(y,y),let(zz,lam(z,z),let(yyzz,app(yy,zz),app(xx,yyzz))))),R),R=lam(z,z).
:- halt.
% 値
v(N) :- integer(N).
v(lam(X,_)) :- atom(X).
% 式を文脈と、パラメータに分ける
e(E,[],E).
e(app(E,T),app(E2,T),H):-e(E,E2,H).
e(add(V,E),add(V,E2),H):-v(V),e(E,E2,H).
e(add(E,T),add(E2,T),H):-e(E,E2,H).
% 置換
subst(X,T,X,T).
subst(X,T,lam(X1,T1),lam(X1,T1_)) :- subst(X,T,T1,T1_), X \=X1.
subst(X,T,app(T1,T2),app(T1_,T2_)) :- subst(X,T,T1,T1_), subst(X,T,T2,T2_).
subst(X,T,add(T1,T2),add(T1_,T2_)) :- subst(X,T,T1,T1_), subst(X,T,T2,T2_).
subst(_,_,E,E).
% ワンステップ実行
eval1(app(lam(X,T),U), T_) :- subst(X,U, T,T_).
eval1(add(V1,V2), V) :- v(V1),v(V2), V is V1 + V2.
% 評価文脈を使った実行
eval1(Et,Et_) :-
e(Et,E,T1), Et \= T1, % 文脈を取り出すけど、EtとT1が同じだと無限ループするので排除
eval1(T1,T1_),!,
subst([],T1_,E,Et_). % 文脈の穴を置き換える
% 複数ステップ実行
eval(T,T_) :- writeln(T),eval1(T,T1),eval(T1,T_).
eval(T,T) :- nl.
:- eval(lam(x,x),R),R=lam(x,x).
:- eval(app(lam(x,x),lam(y,y)),R),R=lam(y,y).
:- eval(app(lam(x,x),1),R),R=1.
:- eval(app(lam(x,x),app(lam(y,y),lam(z,z))),R),R=lam(z,z).
:- eval(app(lam(x,x),app(lam(y,y),1)),R),R=1.
:- eval(app(lam(x,add(x,x)),app(lam(y,y),1)),R),R=2.
:- eval(app(app(lam(x,lam(y,add(x,y))),1),2),R),R=3.
:- halt.
% 値
v(N) :- integer(N).
v(lam(X,_)) :- atom(X).
% 式を文脈と、パラメータに分ける
e(E,[],E).
e(app(V,E),app(V,E2),H):-v(V),e(E,E2,H).
e(app(E,T),app(E2,T),H):-e(E,E2,H).
e(add(V,E),add(V,E2),H):-v(V),e(E,E2,H).
e(add(E,T),add(E2,T),H):-e(E,E2,H).
% 置換
subst(X,T,X,T).
subst(X,T,lam(X1,T1),lam(X1,T1_)) :- subst(X,T,T1,T1_), X \=X1.
subst(X,T,app(T1,T2),app(T1_,T2_)) :- subst(X,T,T1,T1_), subst(X,T,T2,T2_).
subst(X,T,add(T1,T2),add(T1_,T2_)) :- subst(X,T,T1,T1_), subst(X,T,T2,T2_).
subst(_,_,E,E).
% ワンステップ実行
eval1(app(lam(X,T),V), T_) :- v(V), subst(X,V, T,T_).
eval1(add(V1,V2), V) :- V is V1 + V2.
% 評価文脈を使った実行
eval1(Et,Et_) :-
e(Et,E,T1), Et \= T1, % 文脈を取り出し、無限ループ防止
eval1(T1,T1_),!,
subst([],T1_,E,Et_). % 文脈の穴を置き換える
% 複数ステップ実行
eval(T,T_) :- writeln(T),eval1(T,T1),eval(T1,T_).
eval(T,T) :- nl.
:- eval(lam(x,x),R), R=lam(x,x).
:- eval(app(lam(x,x),lam(y,y)),R), R=lam(y,y).
:- eval(app(lam(x,x),1),R), R=1.
:- eval(app(lam(x,x),app(lam(y,y),lam(z,z))),R), R=lam(z,z).
:- eval(app(lam(x,x),app(lam(y,y),1)),R), R=1.
:- eval(app(lam(x,add(x,x)),app(lam(y,y),1)),R), R=2.
:- eval(app(app(lam(x,lam(y,add(x,y))),1),2),R), R=3.
:- halt.
/*
Standard call-by-need reduction.
Syntactic Domains
Variables x,y,z
Values V,W ::= λx.T
Terms S,T,U ::= V | T U
Answers A,Ai ::= λx.T | let x = T in A
Evaluation Contexts E,Ei ::= [] | E T | let x = T in E
| let x = E0 in E1[x]
Standard Reduction Rules
(Is) (λx.T) U -> let x = U in T
(Vs) let x = V in E[x] -> let x = V in E[V]
(Cs) (let x = S in A) U -> let x = S in A U
(As) let y = (let x = S in A) in E[y] -> let x = S in let y = A in E[y]
References
[1] Z. M. Ariola and M. Felleisen. The call-by-need lambda calculus.
Journal of Functional Programming, 7(3):265–301, 1997.
[2] Z. M. Ariola, M. Felleisen, J. Maraist, M. Odersky, and P. Wadler.
A call-by-need lambda calculus. In P. Lee, editor, Proceedings of
the Twenty-Second Annual ACM Symposium on Principles of Programming
Languages, pages 233–246, San Francisco, California, Jan.
1995. ACM Press.
[3] DANVY, Olivier; ZERNY, Ian. A synthetic operational account of
call-by-need evaluation. In: Proceedings of the 15th Symposium on
Principles and Practice of Declarative Programming.
ACM, 2013. p. 97-108.
*/
:- initialization(main).
:- op(920, xfx, [ --->, -->> ]).
:- op(500, yfx, $).
:- op(1200, xfx, [ -- ]).
term_expansion(A -- B, B :- A).
% Values
v(X) :- atom(X).
v(X->_) :- atom(X).
v(N) :- integer(N).
% Answers
a(N,N) :- integer(N).
a(X->T,X->T).
a(let(_=_,A),A_) :- a(A,A_).
% e(expression,evaluation contexts,param)
e(E,[],E).
e(let(X=T,E),let(X=T,E_),H):- e(E,E_,H).
e(let(X=E0,E1x),let(X=E0_,E1x),H):- e(E0,E0_,H), e(E1x,_,X).
e(E$T,E_$T,H):-e(E,E_,H).
e(E+T,E_+T,H):-e(E,E_,H).
e(T+E,T+E_,H):-e(E,E_,H).
subst(X,T,X,T).
subst(X,T,X1->T1,X1->T1_) :- subst(X,T,T1,T1_), X \=X1.
subst(X,T,T1$T2,T1_$T2_) :- subst(X,T,T1,T1_), subst(X,T,T2,T2_).
subst(X,T,T1+T2,T1_+T2_) :- subst(X,T,T1,T1_), subst(X,T,T2,T2_).
subst(X,T,let(X1=T1,T2),let(X1=T1_,T2_)) :- subst(X,T,T1,T1_), subst(X,T,T2,T2_), X\=X1.
subst(_,_,E,E).
% one step
/*(Is)*/ (X->T)$U ---> let(X=U,T).
/*(Vs)*/ let(X=V,Ex) ---> let(X=V,EV) :- v(V),e(Ex,E,X),subst([],V,E,EV).
/*(Cs)*/ let(X=S,A)$U ---> let(X=S,A$U) :- a(A,_).
/*(As)*/let(Y=let(X=S,A),Ey) ---> let(X=S,let(Y=A,Ey)) :-a(A,_),e(Ey,_,Y).
A1+A2 ---> N :- a(A1,N1),a(A2,N2), integer(N1),integer(N2), N is N1 + N2.
/*evaluation contexts*/ Et ---> Et_ :- e(Et,E,T), Et \= T, T ---> T_,!, subst([],T_,E,Et_).
% multi step
T -->> T_ :- writeln(T),T ---> T1,!,T1 -->> T_.
T -->> T_ :- a(T,T_),(T=T_;writeln(T_)),nl,!.
% tests
:- e(let(x=(y->y),x),E,P), E:P=let(x=(y->y),[]):x.
:- e(let(x=(y->y),x$x),E,P), E:P=let(x=(y->y),[]$x):x; writeln("error";E:P),fail.
:- e(y->y,E,P), E:P=[]:(y->y).
:- e(let(y=(z->z),y),E,P), E:P=let(y=[],y):(z->z); writeln("error";E:P),fail.
:- e(let(x=let(y=(z->z),y),x),E,P), E:P=let(x=let(y=[],y),x):(z->z);writeln("error";E:P),fail.
:- (x->x) -->> R, R=(x->x).
:- (x->x)$(y->y) -->> R, R=(y->y).
:- (x->x)$((y->y)$(z->z)) -->> R, R=(z->z).
:- 1 -->> R, R=1.
:- (x->x)$((y->y)$1)-->>R, R=1.
:- ((x->x+x)$((y->y)$1))+((z->z)$10)-->>R, R=12.
:- (x->y->x+y)$1$2-->>R, R=3.
:- let(x=let(y=2,y+1),((z->z)$x+1)+let(y=x,y+x))-->>R, R=10.
:- ((z->z)$1)+((z->z)$2)-->>R, R=3.
:- let(x=1,(z->z)$x)+let(x=2,(z->z)$x)-->>R, R=3.
:- halt.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment