UserFromTheSpace
UserFromTheSpace

Reputation: 77

Prolog select only first solution

I have this code that return a lot of solutions, but I only need the first list, I think that I must work with some cut but I'm new to Prolog and I don't find where i must put it.

list_s(_,[],_) :-
    !.
list_s(P,[P|Ps],ListS) :-
    list_slope(P,Ps,ListS).
list_s(pt(X,Y),[pt(A,B)|Ps],ListS) :-
    angle(pt(X,Y),pt(A,B),R),
    new_s(R,pt(A,B),Ns),
    append(Nls,[Ns],ListS),
    !,
    list_s(pt(X,Y),Ps,Nls).

I have tried to put it after the append/3 but that doesn't work. How can I fix this?

EDIT: I think that the problem is with the append maybe i need change or improve this function.

EXAMPLE:

1 ?- list_slope(pt(2,2),[pt(1,1),pt(2,9),pt(3,8),pt(4,7)],L).

L = [slope(0.3805063771123649, pt(4, 7)), slope(0.16514867741462683, pt(3, 8)), slope(0.0, pt(2, 9)), slope(0.7853981633974483, pt(1, 1))] ;

L = [_G2260, slope(0.3805063771123649, pt(4, 7)), slope(0.16514867741462683, pt(3, 8)), slope(0.0, pt(2, 9)), slope(0.7853981633974483, pt(1, 1))] ;
L = [_G2260, _G2266, slope(0.3805063771123649, pt(4, 7)), slope(0.16514867741462683, pt(3, 8)), slope(0.0, pt(2, 9)), slope(0.7853981633974483, pt(1, 1))] ;

L = [_G2260, _G2266, _G2272, slope(0.3805063771123649, pt(4, 7)), slope(0.16514867741462683, pt(3, 8)), slope(0.0, pt(2, 9)), slope(0.7853981633974483, pt(1, 1))]

Upvotes: 0

Views: 1169

Answers (2)

Paulo Moura
Paulo Moura

Reputation: 18663

Instead of using cuts or discarding (apparently wrong) solutions, best to rewrite the code to avoid the unwanted choice-points in the first place. For example, assuming that the predicate is called always with the first two arguments bound:

list_slope(Point, Points, Slopes) :-
    % change argument order to exploit
    % first-argument indexing
    list_slope_(Points, Point, Slopes).

list_slope_([], _, []).
list_slope_([pt(A,B)| Points], pt(X,Y), [Slope| Slopes]) :-
    angle(pt(X,Y), pt(A,B), Angle),
    new_slope(Angle, pt(A,B), Slope),
    list_slope_(Points, pt(X,Y), Slopes).

This will give, however, the slopes in the reverse order compared with your original code. If the reverse order is required, you can get it easily using an accumulator:

list_slope(Point, Points, Slopes) :-
    % change argument order to exploit
    % first-argument indexing
    list_slope_(Points, Point, [], Slopes).

list_slope_([], _, Slopes, Slopes).
list_slope_([pt(A,B)| Points], pt(X,Y), Acc, Slopes) :-
    angle(pt(X,Y), pt(A,B), Angle),
    new_slope(Angle, pt(A,B), Slope),
    list_slope_(Points, pt(X,Y), [Slope| Acc], Slopes).

Upvotes: 1

Wouter Beek
Wouter Beek

Reputation: 3407

If you want only the first result of a Prolog predicate you can simply do

once(some_predicate(Result))

Upvotes: 1

Related Questions