Search code examples
prolog

Printing out a dynamically sized truth table using lists in prolog


I have created a clause table for creating a truth table given 2 premises and 3 predicates and a conclusion:

bool(true).
bool(false).
% Function for printing out the table
table(P,Q,R,E1,E2,Conclusion):-
    write('P\tQ\tR\t'), 
    write(E1), write('\t'), 
    write(E2), write('\t'), 
    write(Conclusion), 
    write('\tCheck'), nl,
    printValues(P,Q,R,E1,E2,Conclusion).

% Function prints out the truth tables.
printValues(P,Q,R,E1,E2,Conclusion):-
    bool(P), bool(Q), bool(R),  % Get the permutations of all the possible combinations of true and false.
    write(P), format(P), write('\t'), % Print each true/false.
    write(Q), format(Q), write('\t'),
    write(R), format(R), write('\t'),
    writePremise(E1), write('\t'), % Evaluate the premises and write out the result.
    writePremise(E2), write('\t\t'),
    writePremise(Conclusion), write('\t\t'),    % Evaluate the conclusion and write out the result.
    writeCheck(E1, E2, Conclusion). % perform check to see if valid.
% Evalutes a given premise and writes out true or false.
writePremise(E):-
    (E -> write('true'); write('false')).
writeCheck(E1, E2, Conclusion):-
    ((E1,E2 -> (Conclusion -> write('okay'); write('invalid')));
    write('okay')), nl, fail.

Which given a query such creates a truth table:

| ?- table(P,Q,R,and(P,Q),P,my_not(Q)).
P       Q       R       and(_26,_27)    _26     my_not(_27)     Check
true    true    true    true    true            false           invalid
true    true    false   true    true            false           invalid
true    false   true    false   true            true            okay
true    false   false   false   true            true            okay
false   true    true    false   false           false           okay
false   true    false   false   false           false           okay
false   false   true    false   false           true            okay
false   false   false   false   false           true            okay

no

Now I want to change create a new clause that can take in two lists - one for predicates and one for premises.

It currently looks like so:

tableMoreDynamic(Predicates,Premises, Conclusion):-
    writePredicates(Predicates),
    writePremises(Premises),
    writePremise(Conclusion), write('\t\t'),
    writeDynamicCheck(Premises, Conclusion),
    nl, fail.

writePredicates([]):- true.
writePredicates([HEAD|TAIL]):-
    bool(HEAD), 
    write(HEAD) , write('\t'),
    writePredicates(TAIL).

writePremises([]):- true.
writePremises([HEAD|TAIL]):-    
    writePremise(HEAD), write('\t'),
    writePremises(TAIL).

writeDynamicCheck(Premises, Conclusion):-
    (checkList(Premises) -> (Conclusion -> write('okay'); write('invalid')); 
    write('okay')).

checkList([]):- true.
checkList([HEAD|TAIL]):-
    HEAD,
    checkList(TAIL).

It currently works in that it prints out the correct values for the premises, conclusion and the valid check. However due to backtracking in the writePredicates clause it doesn't print out all the different predicates on each line:

| ?- tableMoreDynamic([P,Q],[P],my_not(P)).
true    true    true    false           invalid
false   true    false           invalid
false   true    false   true            okay
false   false   true            okay

As such I was wondering if there was a way to know if you have backtracked within this function (so that we can reprint earlier values on that line). Or perhaps a way to map the bool clause to a list so we can just print out that list. Apologies for the wall of code. Thanks


Solution

  • As such I was wondering if there was a way to know if you have backtracked within this function (so that we can reprint earlier values on that line).

    There is probably some ingenious hack to do this, but it would be a very confusing solution to a confusing interpretation of the problem. The problem itself is simple:

    Or perhaps a way to map the bool clause to a list so we can just print out that list.

    Yes. And you already know how to do it, since this is what you are doing inside writePredicates anyway! The only thing you're missing is that you should do this "labeling" of a complete list of bools before starting printing, rather than interleaving the labeling and printing of individual elements.

    So all you need is this:

    bools([]).
    bools([Bool | Bools]) :-
        bool(Bool),
        bools(Bools).
    
    tableMoreDynamic(Predicates,Premises, Conclusion):-
        bools(Predicates),
        writePredicates(Predicates),
        ...
    

    leaving the rest of your code unchanged. (You can remove the bool call inside writePredicates, it no longer does anything.)

    And this prints the complete table:

    ?- tableMoreDynamic([P,Q],[P],my_not(P)).
    true    true    true    false       invalid
    true    false   true    false       invalid
    false   true    false   true        okay
    false   false   false   true        okay
    false.
    

    If you don't want to write out the entire recursion for bools yourself, there might be an even shorter solution, if your Prolog provides some higher-order predicates. For example, in SWI-Prolog you can just call:

    maplist(bool, Predicates)
    

    without needing to define a bools predicate at all.