Question

My list (which in turn contains lists) contains many different types of elements (obj1(), obj2(), obj3..). I want to access each element in this list and do something only if the element I'm currently accessing is of type obj2(_).

listObj = [[ obj1(_), obj2(_), obj1(_) ],
          [ obj3, obj3, obj2(_), obj1(_)]],

foreach ((X, listObj)), 
%% if X is obj2(_) -> doSomething using x's _ value,
%% otherwise skip this element
).
Was it helpful?

Solution

Using lists of lists usually hints at a bad representation. Several systems provide a flatten/2 library predicate over lists that may be useful, however, if you cannot avoid this representation. Assuming that the list of lists in your example have been flatted, you should be able to write a simple recursive predicate to walk over the list and process each element that satisfies your criteria. Something like:

process([]).
process([Element| Elements]) :-
    (   Element = obj2(Arg) ->
        do_something(Arg)
    ;   true
    ),
    process(Elements).

Details, however, will depend on several factors that you don't specify. For example, what does it mean if processing of an obj2(_) element fails? Failure of processing the list (as in the predicate sketched above)? Continue to the next element? Are the list elements independent or may share variables? Some Prolog systems also provide foreach/2 and forall/2 predicates that might be useful for a compact (but not necessarily more efficient) solution.

OTHER TIPS

I think this is just a basic recursion question - how to iterate through a list, and use pattern matching on the head. If so, this should do

% case 1 - end recursion
listiter([]).

% case 2 - list head obj2 matches
listiter([obj2(Obj_2_Value)|T]) :-
    write(Obj_2_Value), nl,
    listiter(T).

% case 3 - case 2 failed, just recurse, ignoring head
listiter([_|T]) :-
    listiter(T).

In your 'real' code, replace, the 'write/nl' predicates with whatever you want to really do with obj2()'s value.

?listiter([obj1(brown), obj2(hello), obj3(fred), obj2(stack), obj4(bun), obj2(overflow)]).
hello
stack
overflow
true .

Or a shorter way, using the built-in maplist/1:

% match if item is obj2()
dosomething(obj2(Obj_2_Value)) :-
    write(Obj_2_Value), nl.

% not object 2 - still return true, but don't do anything
dosomething(_).


?- maplist(dosomething, [obj1(brown), obj2(hello), obj3(fred), obj2(stack), obj4(bun), obj2(overflow)]).
hello
stack
overflow
true .

the easier way (but please note: Variables start Uppercase):

..., flatten(ListObj, F), member(obj2(V), F), process(V), ...

To avoid flattening the list, we must make a predicate, and introduce recursion:

nested_member(V, X) :-
    member(T, X),
    ( is_list(T) -> nested_member(V, T) ; V = T ).

with that

?- nested_member(obj2(V),[[1,[2,obj2(3),a],obj2(b),4]]).
V = 3 ;
V = b ;
false.
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top