:- module(_,_,[doccomments,sr/bfall]).

%! \title Polymorphic member

% \module We can write a 'polymorphic' member that works 
% with both lists and trees. 

%! lt_member(X,LT): X is a member of the list or tree LT.

lt_member(X, [X|Y]) :- list(Y).
lt_member(X, [_|T]) :- lt_member(X, T).

lt_member(X, tree(X, L, R)) :- binary_tree(L), binary_tree(R).
lt_member(X, tree(_Y, L, _R)) :- lt_member(X, L). 
lt_member(X, tree(_Y, _L, R)) :- lt_member(X, R).

% Try:
% ?- lt_member(M,[1,2,3]).
% ?- tree_example(_T), lt_member(M,_T).

% However: 
% ?- lt_member(M,T).
% We also get elements that are of mixed type --because 
% that is what we specified! If we want to separate the 
% types: 

%! lt_member_separate(X,LT): X is a member of the list or tree LT.
lt_member_separate(X, Y) :- list_member(X, Y).
lt_member_separate(X, Y) :- tree_member(X, Y).

% Try:
% ?- lt_member_separate(M,[1,2,3]).
% ?- tree_example(_T), lt_member_separate(M,_T).
% And: 
% ?- lt_member_separate(M,T).
% Now we obtain separated types!




% Auxiliary predicates: 
:- redefining(list/1).

list([]).
list([_|Y]) :-
     list(Y).

list_member(X,[X|L]) :-
    list(L).
list_member(X,[_|T]) :- 
    list_member(X,T).

tree_member(X,tree(X,Left,Right)) :- 
    binary_tree(Left),
    binary_tree(Right).
tree_member(X,tree(_,Left,_Right)) :- 
    tree_member(X,Left). 
tree_member(X,tree(_,_Left,Right)) :- 
    tree_member(X,Right).

binary_tree(void).
binary_tree(tree(_Element,Left,Right)) :- 
    binary_tree(Left),
    binary_tree(Right).

tree_example(  tree( a,
                   tree( b,
                         void,
                         void
                       ),
                   tree( c,
                         tree( b,
                               void,
                               void
                               ),
                         void
                       )
                   )).
