% synth +G +R -A
% check +G +M +A


check(G, lam(X, M), imp(A, B) :-
    check([tp(X, A) | G], M, B).

% with the following rule, we see an occurs check problem
% check(G, R, A) :-
%    synth(G, R, B), 
%    A = B.

% this does not actually solve the occurs check problem
% rather, here we just avoid any interesting unifications
check(G, R, A) :-
    synth(G, R, A).

check(G, pair(M, N), and(A, B)) :-
    check(G, M, A),
    check(G, N, B).

synth([tp(X, A) | _], X, A).

synth([tp(X, A) | _], X, B) :-
    unify_with_occurs_check(A, B).

% accounts for shadowing
synth([tp(Y, _) | G, X, A]) :- 
    Y \= X, 
    synth(G, X, A).

synth ([_ | G], X, )
    :- synth(G, X, A).

synth(G, app(R, M), B) :-
    synth(G, R, imp(A, B)),
    check(G, M, A).

synth(G, pi1(R), A) :-
    synth(G, R, and(A, _)).

synth(G, pi2(R), B) :-
    synth(G, R, and(_, B)).