5

If I have a list of predicates in Prolog like [flies, swims], how can I build a predicate that is the conjunction of all the predicates in the list, ie fliesAndSwims(X) :- flies(X), swims(X).?

Alternatively, is there a better way of building up a predicate at runtime like this without putting the component predicates in a list and building the compound one from them when needed?

EDIT: So it turns out this is a duplicate of List of predicates in Prolog. I had previously found that answer, but I thought that it only returned whether a given atom matched every predicate in the list. I didn't realise that you can pass a variable instead of an atom and have it return every case that matches as well.

Community
  • 1
  • 1
lavelle
  • 1,446
  • 1
  • 17
  • 30

2 Answers2

2

Here's an alternative to updating Prolog's dynamic database... You could use a meta-predicate like maplist/2, IMHO ideally in combination with Prolog lambda expressions.

First, some sample (super-incomplete) definitions of flies/1 and swims/1:

flies(duck).
flies(eagle).

swims(penguin).
swims(ostrich).
swims(duck).
swims(kiwi).
swims(eagle).

Now let's do a query:

?- use_module(library(lambda)).
true.

?- maplist(X+\Pred^call(Pred,X), [flies,swims]).
X = duck ;
X = eagle.
repeat
  • 18,496
  • 4
  • 54
  • 166
  • That worked great, thanks a lot. The lambda library worked well, but could you explain how you would do the same in vanilla prolog? I'm still learning so I want to know how the stuff I'm using works rather than blindly copying. I'm guessing it's the equivalent of lambda/anonymous functions in other languages, just a convenience to let you define them inline rather than as a separate declaration? – lavelle Apr 26 '15 at 15:51
  • 1
    Actually, `library(lambda)` **is** "vanilla" ISO Prolog:) As stated on the page linked: "No syntax or compiler extension is needed." – repeat Apr 26 '15 at 15:58
2

library(lambda) is powerful, but it has a cost. If you think 'simpler is better' (wrt debugging, specially...) consider

call_unary_list([], _).
call_unary_list([P|Ps], X) :-
    call(P, X),
    call_unary_list(Ps, X).

let's compare the performances:

compare_call_list :-
    findall(flies, between(1,100000,_), L),
    time(call_unary_list(L, _)),
    time(maplist(call_unary(_), L)),
    time(maplist(X+\Pred^call(Pred,X), L)).

call_unary(X, P) :- call(P, X).

?- compare_call_list.
% 200,000 inferences, 0.123 CPU in 0.123 seconds (100% CPU, 1629657 Lips)
% 300,000 inferences, 0.145 CPU in 0.149 seconds (98% CPU, 2064184 Lips)
% 1,000,001 inferences, 1.286 CPU in 1.297 seconds (99% CPU, 777362 Lips)
true .

the call_unary/2 highlights the arguments swap that's required by the maplist meta predicate

CapelliC
  • 59,646
  • 5
  • 47
  • 90
  • @repeat: I like lambda, actually I used it many times. When using it, I found 'the hard way' some problems. So, specially for beginners, I just prefer explain more basic techniques... – CapelliC Apr 27 '15 at 08:24