Search code examples
prologswi-prolog

How to you list Prolog queries and then print each query and its result(s) programmatically?


I have the following file named movies.pl:

acted_in('Brad Pitt', 'Babel').
acted_in('Cate Blanchett', 'Babel').
acted_in('Sharlto Copley', 'District 9').
acted_in('Sharlto Copley', 'Elysium').
acted_in('Matt Damon', 'Elysium').
acted_in('Sharlto Copley', 'Europa Report').
acted_in('Leonardo DiCaprio', 'Don\'t Look Up').
acted_in('Jonah Hill', 'Don\'t Look Up').
acted_in('Cate Blanchett', 'Don\t Look Up').
acted_in('Adam Sandler', 'Click').
acted_in('Christopher Walken', 'Click').
acted_in('Kate Beckinsale', 'Click').
acted_in('Jonah Hill', 'Click').
acted_in('Leonardo DiCaprio', 'The Aviator').
acted_in('Cate Blanchett', 'The Aviator').
acted_in('Kate Beckinsale', 'The Aviator').
acted_in('Brad Pitt', 'Inglourious Basterds').
acted_in('Melanie Laurent', 'Inglourious Basterds').
acted_in('Michael Fassbender', 'Inglourious Basterds').
acted_in('Diane Kruger', 'Inglourious Basterds').

directed('Alejandro Gonzalez Inarritu', 'Babel').
directed('Neill Blomkamp', 'District 9').
directed('Neill Blomkamp', 'Elysium').
directed('Sebastian Cordero', 'Europa Report').
directed('Adam McKay', 'Don\'t Look Up').
directed('Frank Coraci', 'Click').
directed('Martin Scorsese', 'The Aviator').
directed('Quentin Tarantino', 'Inglourious Basterds').

released('Babel', 2006).
released('District 9', 2009).
released('Europa Report', 2013).
released('Don\'t Look Up', 2021).
released('Click', 2006).
released('The Aviator', 2004).
released('Inglourious Basterds', 2009).

I want to run a bunch of queries on it, automatically, without me having to interactively enter in the queries. When entered in interactively, some sample queries look like:

?- released(Movie, 2009), directed(Director, Movie).
Movie = 'District 9',
Director = 'Neill Blomkamp' ;
Movie = 'Inglourious Basterds',
Director = 'Quentin Tarantino'.

?- acted_in(Actor, 'Click'), acted_in(Actor, 'The Aviator').
Actor = 'Kate Beckinsale' ;
false.

?- directed(Director_1, Movie), directed(Director_2, Movie), \+ Director_1 = Director_2.
false.

Since these are ran interactively, I know what queries were asked with what results. When I run them programmatically, I basically want the exact same output but with the query that produced each result printed above it. I've seen some things with the initialization/1 directive after searching, but I wasn't for sure how to list the queries and then get them printed out with their results. I am still new to Prolog and would like to continue along the current book I'm going through without getting too bogged down with this diversion, although the diversion will help going through the book. I'd just like a simple thing I can implement so that I can run a list of queries when the file is loaded, the queries themselves are printed out followed by their results.

Thanks!


Solution

  • One way to achieve this is to define these two helper methods:

    % Obtain one possible substitution ("Result") for Query
    get_result(Query, Result) :-
        term_string(Term, Query, [variable_names(VariableNames)]),
        Term,
        Result = VariableNames.
    
    % Find and print all substitutions for Query, fail if empty
    log_query(Query) :-
        format("Evaluating: ~w ~n", [Query]),
        findall(Result, get_result(Query, Result), Results),
        not(length(Results,0)),
        writeln(Results).
    

    With this we can define a predicate to run our queries:

    main :-
        log_query("released(Movie, 2009), directed(Director, Movie)."),
        log_query("acted_in(Actor, 'Click'), acted_in(Actor, 'The Aviator')."),
        log_query("directed(Director_1, Movie), directed(Director_2, Movie), \\+ Director_1 = Director_2.").
    

    And then to add this clause to run this predicate on initialization:

    :- initialization main.
    

    This will log the following at the start of a session:

    Evaluating: released(Movie, 2009), directed(Director, Movie). 
    [[Movie=District 9,Director=Neill Blomkamp],[Movie=Inglourious Basterds,Director=Quentin Tarantino]]
    Evaluating: acted_in(Actor, 'Click'), acted_in(Actor, 'The Aviator'). 
    [[Actor=Kate Beckinsale]]
    Evaluating: directed(Director_1, Movie), directed(Director_2, Movie), \+ Director_1 = Director_2. 
    Warning: Initialization goal failed