9
votes

I need to do this homework assignment using prolog (SWI-flavor) and cant get my head around some things.

For example, if i want to iterate through a list and add its elements to another, but ONLY if they meet certain condition, how would I go about it? I can add them all, or none, but if I add clause that checks this condition, the whole recursion turns out as "false". I understand why this is, but have no idea how to fix it. Basically what i want is:

goal(Stuff) :- do_something(X),
               only_do_this_if_something(Y),
               always_do_this(Z).

Currently, if only_do_this_if_something(Y) fails, also always_do_this(Z) doesnt happen as the whole goal turns false...

4
+1 for being honest about needing help for homework assignment.csl
@GuyC: There is nothing specific to SWI here!false

4 Answers

11
votes

you can use the if structure:

<condition> -> (do_something) ; (do_something else)

in this case:

goal(Stuff):-
  do_something(X),
  if_something(Y)-> do_this(Y) ; true,
  always_do_this(Z).

or you simply write two clauses like:

goal(Stuff):-
  do_something(X),
  conditional_stuff(Y),
  always_do_this(Z).

conditional_stuff(Y):-
  condition(Y),
  do_this(Y).

conditional_stuff(_).
1
votes

Check the following programming pattern, which is used quite a lot in Prolog:

  • Iterate through the list, one element at a time
  • Set a base case for the recursion
  • In one clause, check whether the conditions apply and do something, then continue with recursion
  • In the next clause skip the item and continue with recursion

You have to either use the cut (!) to forbid backtracking or explicitly check that the condition do not apply in the latter clause.

Note that you said that you wanted to have an output list with the items for which 'something' applied (which is not what you wrote in your code)...

Applying this pattern to your problem it would look something like this:

myRecursion([], []). % This is the base case
myRecursion([Item|Tail], [Item|NTail]):-
  something_applies(...),
  do_something(...),
  only_do_this_if_something(...),
  always_do_this(...).
  myRecursion(Tail, NTail).
myRecursion([Item|Tail], NTail):-
  not(something_applies(...)),
  do_something(...),
  always_do_this(...),
  myRecursion(Tail, NTail).
1
votes

If I understand correctly, then what you need is a predicate like include/3:

include(:Goal, +List1, ?List2)
    Filter elements for which Goal succeeds. True if List2 contains
    those elements Xi of List1 for which call(Goal, Xi) succeeds.

Usage example:

?- include(number, [a(b), 2, _, 1.2, C, '1'], L).
L = [2, 1.2].

Now your homework becomes "how to implement include/3". Once you have implemented your version of include/3 you can check if it matches SWI's version by looking at its source code: listing(include).

0
votes

try the ignore/1 predicate:

goal(Stuff) :-
    do_something(X)
    ignore(only_do_this_if_something(Y)),
    always_do_this(Z).

ignore/1 calls the only argument and succeeds whenever it fails or not:

ignore(X) :- X, !.
ignore(_).