1

I have a knowledgebase that looks something like this

fact1(1, _, a, _, _).
fact1(2, _, c, _, _).
fact1(3, _, d, _, _).
fact1(4, _, f, _, _).

fact2(_, 1, b, _, _).
fact2(_, 2, c, _, _).
fact2(_, 4, e, _, _).

For every fact1 & fact2, where (in this example) the numbers match up, I want to have a list of the corresponding letters as tuples. I would like to use findall/3 and only one predicate for this.

I have asked a question here before on how to solve something similar, where the answer was using two predicates. That solution looked like this:

find_item((Val1,Val2)):-
    fact1(A, _, Val1, _, _),
    fact2(_, A, Val2, _, _).`

test(Items) :-
    findall(Item,find_item(Item),Items).

The result for the given example of facts, should look like this:

[(a, b),  (c, c),  (f, e)]

Can the two predicates be combined using just findall/3?

Guy Coder
  • 24,501
  • 8
  • 71
  • 136
HappyHippo
  • 152
  • 3
  • 11
  • 1
    I changed the title so that others could easily find this and learn from it. While your title was correct, it was too specific and other might pass it by even though it would have what they needed. – Guy Coder Apr 11 '19 at 13:33
  • Alright thank you. Looks like I have plenty to learn not only in prolog but in SO too. – HappyHippo Apr 11 '19 at 13:58
  • 1
    Note that, depending on the Prolog system, using control constructs (e.g. conjunctions, disjunctions, if-then-else, ...) in the `findall/3` goal argument can result in performance penalties. – Paulo Moura Apr 11 '19 at 15:18
  • @PauloMoura Your note carries more weight to be just a comment. If it were me I would add it as an additional answer. Many people don't read comments. – Guy Coder Apr 11 '19 at 18:07

1 Answers1

2

You can inline procedure find_item/1 as the goal of findall/3 (use a conjunction of goals instead of a single goal):

test(Items):-
  findall((Val1, Val2), (fact1(A, _, Val1, _, _), fact2(_, A, Val2, _, _)), Items).
gusbro
  • 22,357
  • 35
  • 46