0

By the time I'm learning Prolog I encountered on a problem. I'm trying to make function like this

   ?- less_than([1,2,3,2,1,5],3,Y).
      Y= [1,2,2,1]

Because I was learning object-oriented programming I stacked with this and can't figure out how to solve. This is mine code:

  less_than([],X,Y).
  less_than([H|T], X, [H1|T1]) :-
            H<X, less_than(T,X,H).

And also, I tried with findall:

  less_than([],X,Y).
  less_than([H|T],X,[H1|T1]) :-
            findall(H, (H<X, less_than(T,X,Y)), Z).

Where I'm getting this result:

Y = [_G2274|_G2275]  for ?- less_than([1,2,3,4,5],3,X)

I know that they are unknown values but how to set values in that list? I tried to change Y with and H but it wont work.

I tried to debug it but with no success, it keeps falling apart and this is only logical explanation how to solve it for me. Any1 has an idea?

false
  • 10,264
  • 13
  • 101
  • 209
iMajna
  • 489
  • 4
  • 28
  • 1
    Possible duplicate of [Numbers in a list smaller than a given number](http://stackoverflow.com/questions/32260202/numbers-in-a-list-smaller-than-a-given-number) –  Nov 01 '16 at 11:20

1 Answers1

3

I won't solve the whole issue for you, but I would like to show you how you can approach such issues in general.

A major advantage of Prolog is that you can debug issues declaratively. This means that you use logical properties of Prolog to locate the causes of unintended answers.

For example, in your case, you have the program:

less_than([], X, Y).
less_than([H|T], X, [H1|T1]) :-
        H < X,
        less_than(T, X, H).

and the following unintended failure of a query:

?- less_than([1,2,3,2,1,5], 3, Y).
false.

Let us use the following definition to generalize a Prolog program, like in GUPU:

:- op(950,fy, *).

*_.

For example, consider the following generalization, which we obtain by placing (*)/1 in front of all goals:

less_than([], X, Y).
less_than([H|T], X, [H1|T1]) :-
        * H < X,
        * less_than(T, X, H).

With this generalization, we have:

?- less_than([1,2,3,2,1,5],3,Y).
Y = [_G946|_G947].

So, while this is now too general, at least the query succeeds.

By refining the generalization, we can narrow down the exact cause of the problem. For example:

less_than([], X, Y).
less_than([H|T], X, [H1|T1]) :-
        * H < X,
        less_than(T, X, H).

This again yields:

?- less_than([1,2,3,2,1,5],3,Y).
false.

Observe that adding further goals can at most specialize the program, never generalize it. Therefore, the remaining fragment must be generalized if we want this query to succeed at all.

So, if you want your query to succeed at all, you must make at least the following fragment succeed for the query:

less_than([], X, Y).
less_than([H|T], X, [H1|T1]) :-
        less_than(T, X, H).

Why does this currently fail? Try the following further generalization:

less_than([], /*X*/_, /*Y*/_).
less_than([H|T], /*X*/_, [/*H1*/_|/*T1*/_]) :-
        less_than(T, /*X*/_, H).

This still fails:

?- less_than([1,2,3,2,1,5],3,Y).
false.

So, we have now reduced this to:

less_than([], _, _).
less_than([H|T], _, [_|_]) :-
        less_than(T, _, H).

And now the point: Interestingly, the following generalization succeeds:

less_than([], _, _).
less_than([H|T], _, [_|_]) :-
        less_than(T, _, /*H*/_).

Therefore, this last argument of the call of less_than/3 is a hot candidate for closer scrutiny...

false
  • 10,264
  • 13
  • 101
  • 209
mat
  • 40,498
  • 3
  • 51
  • 78
  • I have made some changes and I think the program is working now. `less_than([],X,[]). less_than([H|T], X, [H|List]) :- H=X, less_than(T,X, List). ` Actually I wrote all down except the last **less_than(T, X, List).** . Why is that? I figured out that I need something which will iterate through all list but I havent known how not to add that numbers `H>=X` to my last parameter. So my question now is, how is the last line different from less_than/3? I just can't figure it out in my brain, can you help me explain it? – iMajna Nov 01 '16 at 11:28
  • The last line *is* a goal of the form `less_than/3`. A good way to understand the definition is to read the clauses *declaratively*: **If** it is the case that `H >= X` *and* `List` is the list of elements of `Ts` that are *less than* `X`, **then** `List` is *also* the list of elements that are less than `X` in the list `[H|Ts]`. Analogously for the other two clauses, for example: It **is** the case that `[]` is the list of elements less than `X` that also occur in the empty list. Using **constraints** would make your program a lot **more general**, usable in other directions too! – mat Nov 01 '16 at 11:36