%% -*- prolog -*-

%%% Mad Libs (using difference lists)

%%% Digression: "OCCURS CHECK"

repeat1(X, [X|Xs]) :- repeat(X, Xs).

repeat2(X, Xs) :- Xs=[X|Xs].

%% Occurs check in the unification routine of the Haskell type inference system:
% $ ghci
% Prelude> let badf x = x badf
% <interactive>:4:16:
%     Occurs check: cannot construct the infinite type:
%       t1 = (t1 -> t0) -> t0
%     In the first argument of `x', namely `badf'
%     In the expression: x badf
%     In an equation for `badf': badf x = x badf

%% Prolog does not have an occurs check!

%% concatenate a list of lists to yeild a list.
concat0([], []).
concat0([Xs], Xs).		% bug: two rules matching singleton list
concat0([Xs|Xss], Ys) :- concat0(Xss, Us), append(Xs, Us, Ys).

concat([Xs], Xs).
concat([Xs, Ys | Zss], Us) :- concat(Zss, Zs), append(Xs, Ys, XYs), append(XYs, Zs, Us).
concat([], []).

% [my,dog,bit,the,postman,'!']
sentence(Ws) :-
	nounphrase(NounPhrase),
	verbphrase(VerbPhrase),
	fullstop(Fullstop),
	concat([NounPhrase, VerbPhrase, Fullstop], Ws).

sentence(Ws) :-
	concat([Subject, VerbPhrase, Object, Fullstop], Ws), % really want "nonempty elements concat"?
	nounphrase(Subject),
	verbphrase(VerbPhrase),
	nounphrase(Object),
	fullstop(Fullstop).

nounphrase(N) :- noun(N).
nounphrase(P) :- adjectives(As), noun(N), concat([As, N], P).
noun([dog]).
noun([cat]).
adjectives([]).
adjectives([A|As]) :- adjective(A), adjectives(As).
adjective(red).
adjective(slow).
adjective(angry).
verbphrase([eats]).
verbphrase([runs]).
fullstop(['.']).
