1

I have following data:

item(one, 50, 40).
item(two, 80, 70).
item(three, 100, 55).
item(four, 50, 45).
item(five, 50, 40).
item(six, 80, 70).
item(seven, 100, 55).
item(eight, 50, 45).

I use following command to display all values:

findall((A,B,C), item(A,B,C), L).

However, it displays all items. This can be a problem if there are hundred such entries. How can I display a limited number of items, say 3 in above case?

I see there are some posts on this: Prolog: "findall" for limited number of solutions and Finding up to N unique solutions of a goal in Prolog and Prolog: "findall" for limited number of solutions but I am unable to fit those to my problem.

I am trying following code but it is not picking up the length of the list:

head(N):-
    findall((A,B,C), item(A,B,C),L),
    writeln(L),
    writeln("------ 1 ---------"),
    length(L, N),
    writeln(N),
    writeln("------ 2 ---------"),
    head2(L, N, 0).

head2(L, N, M):-
    M < N, 
    nth0(M, L, Item), 
    writeln(Item),
    X is M+1, 
    head2(L, N, X).

Output:

?- head(3).
[ (one,50,40), (two,80,70), (three,100,55), (four,50,45), (five,50,40), (six,80,70), (seven,100,55), (eight,50,45)]
------ 1 ---------
false.
Community
  • 1
  • 1
rnso
  • 23,686
  • 25
  • 112
  • 234

2 Answers2

1

There's one thing I noticed in the following:

head(N) :-
    findall((A,B,C), item(A,B,C),L),
    writeln(L),
    writeln("------ 1 ---------"),
    length(L, N),
    ...

Considering fundamental Prolog principles: this will succeed only if findall/3 yields a list L and the length of L is exactly N. If you query head(3), and findall/3 yields a list whose length is not 3, then length(L, N) will fail and the following statements (...) will never be called. Of course, since you have a writeln before the failure, the writeln will execute, showing the result you have.

As a general comment, you should try to use variables for results, not writeln statements. writeln is great for prompting a user or tracing specific portions of code, but not for producing results that can be used later.

An alternative approach:

find_n_items(MaxCount, Items) :-
    findall((A,B,C), item(A,B,C), AllItems),
    length(AllItems, AllItemsCount),
    ItemsCount is min(AllItemsCount, MaxCount),
    length(Items, ItemsCount),  % Constrain the length of Items
    append(Items, _, AllItems). % Select ItemCount items from front of AllItems

Here we constrain the length of Result to be the minimum of what findall/3 produces and the requested length limit and take that number of elements from the front of AllResults using append/3.

lurker
  • 56,987
  • 9
  • 69
  • 103
1
:- dynamic limitcount/1.

maxbacktrack :-
    retract(limitcount(Current)),
    Current > 0,
    Next is Current-1,
    assert(limitcount(Next)).

firstN(N,Pred) :-
    retractall(limitcount(_)),
    asserta(limitcount(N)),
    Pred,
    maxbacktrack.

findN(N,Term,Pred,List) :-
    findall(Term,firstN(N,Pred),List).

For example:

?- findN(3,(A,B,C),item(A,B,C),L).
L = [ (one, 50, 40), (two, 80, 70), (three, 100, 55)].
Zebollo
  • 21
  • 1