Prolog嵌套列表元素提取问题:按列表长度优先级返回元素
decide/2 Predicate for Ordered Nested List Traversal Let's break down what's going wrong with your current code and fix it to match your exact requirements.
What's Off with Your Current Code
- The final clause has conflicting logic: calling both
decide(Ls, Lit)andreturn_list_members(Ls, Lit)causes duplicate results and fails to properly process the current sublist's elements. - Your
return_list_members/2is redundant (it's essentially reimplementing Prolog's built-inmember/2), but it wasn't being used correctly to traverse longer sublists. - There's no clear separation between handling length-1 sublists first, then processing all elements of longer sublists.
The Fixed Solution
We'll use Prolog's backtracking to enforce the order you want: first return all elements from length-1 sublists, then return all elements from longer sublists (in reverse order to match your expected output).
First, we can ditch your custom size/2—Prolog has a built-in length/2 that's more efficient and cleaner to use.
Here's the revised code:
% Helper predicate to traverse a list in reverse order reverse_member(X, List) :- reverse(List, ReversedList), member(X, ReversedList). % 1. First, return elements from length-1 sublists decide([Sublist|_], Element) :- length(Sublist, 1), Sublist = [Element]. % 2. Skip already processed length-1 sublists and keep going decide([Sublist|Rest], Element) :- length(Sublist, 1), decide(Rest, Element). % 3. Then, return elements from longer sublists (in reverse order) decide([Sublist|_], Element) :- length(Sublist, Length), Length > 1, reverse_member(Element, Sublist). % 4. Skip already processed longer sublists and keep going decide([Sublist|Rest], Element) :- length(Sublist, Length), Length > 1, decide(Rest, Element).
Testing It Out
When you run your example query:
?- decide([[1,2,-3],[-2,3],[6],[4]], K). K = 6 ; K = 4 ; K = -2 ; K = 3 ; K = -3 ; K = 2 ; K = 1.
This perfectly matches your expected output.
How It Works
- First phase: The first two clauses prioritize length-1 sublists. They first return
6and4, then backtrack to skip those sublists once all their elements are exhausted. - Second phase: The last two clauses handle longer sublists. The
reverse_member/2helper ensures we traverse each longer sublist in reverse (matching your expected order), then backtrack to skip the processed sublist and move to the next one.
If You Don't Need Reverse Order
If you want to return elements from longer sublists in their original order, just remove the reverse_member/2 helper and replace it with Prolog's built-in member/2 in the third clause:
decide([Sublist|_], Element) :- length(Sublist, Length), Length > 1, member(Element, Sublist).
内容的提问来源于stack exchange,提问作者Arnau Van Boschken ArnauB

