Prolog: Maplist appending results to main list instead of sublists

400 Views Asked by At

So I have the simple predicate defined as

pred(Info, List, Result) :-
  maplist(pred_calculate(Info), List, Result).

pred_calculate returns a list of X elements after an operation on a element of list, so for example pred_calculate(Info, List, Result) would return something like [2,3,5]

I want to add all the results of applying the pred_calculate predicate to all the elements of List, the problem I'm running into is that at the moment it's adding all the results from pred_calculate as sublists instead of adding to the single main list only.

So at the moment Result returns [[2,3,5],[5,7,8],[8,9,11]] when it should return only [2,3,5,5,7,8,8,9,11]

How would I go about changing it to fix this behaviour?

2

There are 2 best solutions below

0
fferri On BEST ANSWER

When using foldl/4 with append/3, you have to pass the arguments in the correct order to append, if the order of the items is important1:

pred(Info, List, Result) :-
    maplist(pred_calculate(Info), List, List1),
    foldl([A, B, C] >> append(B, A, C), List1, [], Result).

Also, flatten/2 would achieve the same result, i.e.:

pred(Info, List, Result) :-
    maplist(pred_calculate(Info), List, List1),
    flatten(List1, Result).

1: foldl(append, List1, [], Result) would give you [8,9,11,5,7,8,2,3,5] as result.

0
lurker On

maplist calls pred_calculate(Info) on every corresponding element of List and Result. Perhaps maplist is not what you really want to use here if pred_calculate results in a list on each call since it's not a 1-1 correspondence. You have a 1-to-many and you want the many in one big, flat list. You could use flatten or fold as !joel76 suggests. Or, you could "manually" write your own maplist-like predicate which is very simple - just a basic list recursion and probably using append to achieve each step:

pred(Info, List, Result) :-
    pred(Info, List, [], Result).

pred(Info, [], Result, Result).
pred(Info, [H|T], Acc, Result) :-
    pred_calculate(Info, H, R),
    append(Acc, R, Acc1),
    pred(Info, T, Acc1, Result).