1

I have 2 lists [x1, x2, ...xn] and [y1, y2, ...yn] of the form {0, 1}^n.

I want to generate a new list [a1, a2 ... an] such that ai = xi AND yi for every i from 1 to n (i.e., if x1 = y1 = 1 then a1 = 1 or if x1 = 1, y1 = 0, then a1 = 0)

How can I implement a predicate using recursion?

repeat
  • 18,496
  • 4
  • 54
  • 166
  • 3
    It would be much easier to help you if you showed some code, what you expected from it, what it actually did (as in, try to run it and show the result in your question). You can then ask a specific question, for example, "Why is it that I don't get the expected result using this program". Also, go ahead and add the generic [prolog] tag to the question. –  Nov 12 '15 at 12:18
  • 4
    This is ideally handled using `maplist/3` (look it up). But since you're probably needing to do your own recursion as an assignment, consider the following: (1) you need a base case of what happens when both (or one of?) the lists is empty (`[]`) - so write a predicate to handle the base case. What's the result if one or both lists is `[]`?, then (2) Then write the recursive case: if you are comparing `[X|Xs]` with `[Y|Ys]`, what does the result look like in terms of `X` and `Y`? And what does the recursive call look like to handle the rest of it? Do a little research. – lurker Nov 12 '15 at 15:31
  • @lurker: your comment is a so much better answer... – CapelliC Nov 12 '15 at 18:41

2 Answers2

3

Use and maplist/4 together with Prolog lambdas like this:

?- use_module([library(clpb),library(lambda)]).
true.

?- maplist(\A^B^AB^sat(A*B =:= AB),
           [1,1,0,0],
           [1,0,0,1],
           Products).
Products = [1,0,0,0].
Community
  • 1
  • 1
repeat
  • 18,496
  • 4
  • 54
  • 166
  • 1
    @CapelliC. At first I wrote `AB is A*B`. It amazes me how much better `sat(A*B =:= AB)` is! [tag:clpb] is way underrated... – repeat Nov 12 '15 at 19:47
  • 2
    We don't even know if it is indeed logical-and, looking at the question. All we know is that it only needs to be defined for {0, 1}. –  Nov 12 '15 at 20:54
0

Disclaimer: This answer is just a more explicit version of the comment by @lurker for posterity.

First, how do you do the AND? One simple option is to use a bitwise AND:

and(A, B, R) :- R is A /\ B.

Now, what you want is as simple as:

?- maplist(and, [1, 0, 0, 1], [0, 1, 0, 1], L).
L = [0, 0, 0, 1].

What is this maplist? Since SWI-Prolog's code is both available and easy to browse, you can look at the standard library definition:

maplist(Goal, List1, List2, List3) :-
    maplist_(List1, List2, List3, Goal).

maplist_([], [], [], _).
maplist_([Elem1|Tail1], [Elem2|Tail2], [Elem3|Tail3], Goal) :-
    call(Goal, Elem1, Elem2, Elem3),
    maplist_(Tail1, Tail2, Tail3, Goal).

This is more general than you probably need. First, you don't need to pass and/3 to the predicate that you want to write, you can simply inline it. So, you will replace the call with and or just with the is. Now you also won't need to reorder the arguments, so you don't need to have a predicate and a helper predicate.

There is so much code out there, it is a shame not to look at it and try to learn.

Community
  • 1
  • 1
  • @repeat lambda and clpb. I removed this anyway, as it added nothing of value to the answer. –  Nov 12 '15 at 21:42
  • Getting lambdas right *can* be quite challenging at times, but in simple cases its use is straightforward: Compare (1) `maplist(\A^B^AB^(AB is A*B), As, Bs, ABs)` to (2) `num_num_prod(A,B,AB) :- AB is A*B.` and `maplist(num_num_prod, As, Bs, ABs)`. – repeat Nov 12 '15 at 21:50
  • 1
    @repeat I don't have an argument here, I completely agree. –  Nov 12 '15 at 21:52
  • 1
    As my experience with clpb is very little, I should use it more -- not fear it more. I wonder how (and if) clpb and clpfd can be used together for solving one and the same problem "from different angles"... – repeat Nov 12 '15 at 22:03