% e.g.golorps(10,X,sentence(X,[])).
golorp(X) :- 
		golorp(X,[],W),
		forall(member(One,W),
		      (print(One),nl)).

golorp(X,W0,W) :-  
		once(look(X,Y,W0)), 
		leap(Y,W0,W).

look(X,     barph(var),           _) :- var(X).
look(true,  skip,                 _).
look((X;Y), or(L),                _) :- or2List((X;Y),L0), shuffle(L0,L).
look((X,Y), and(X,Y),             _).
look(X,     do(X),                _) :- predicate_property(X,built_in).
look(\+ X,  not(X),               _).
look(X,     skip,                 W) :- cache(X,F,What),  member(F=What,W).
look(X,     remember(F,What,X,L), _) :- cache(X,F,What), clauses(X,L).
look(X,     anybody(X,L),         _) :-  clauses(X,L).

leap(skip,                 W ,W).
leap(barph(Why),           W ,W) :- format('% ERROR: ~p.~n',Why),fail.
leap(do(X),                W ,W) :- call(X).
leap(and(X,Y),             W0,W) :- golorp(X,W0,W1),  golorp(Y,W1,W).
leap(not(X),               W ,W) :- \+ golorp(X,W,_).
leap(or(L),                W0,W) :- member(X,L), golorp(X,W0,W).
leap(remember(F,What,X,L), W0,W) :- member(X/Body,L), golorp(Body,[F=What|W0],W).
leap(anybody(X,L),         W0,W) :- member(X/Body,L), golorp(Body,W0,W).

or2List((X;Y),[X|Rest]) :- !,or2List(Y,Rest).
or2List(X,    [X]).

clauses(X,Bodies) :-
	findall(X/Body, clause(X,Body), Bodies0),
	shuffle(Bodies0,Bodies).

shuffle([],[]).
shuffle([H|T], [One|Rest]) :- 
    oneLess([H|T], One, Less), 
    shuffle(Less,Rest).

oneLess(L0,Pruned,L) :-
    length(L0,N0),
    N is random(N0),
    oneLess1(N,L0,Pruned,L).

oneLess1(0,  [H|T],H,T).
oneLess1(N0, [H|T],Out, [H|Rest]) :-
    N0 > 0,
    N is N0 - 1,
    oneLess1(N,T,Out,Rest).


within(X,L) :- var(L) -> L = [X] ; member(X,L).
