mercury

How to check if a variable is instantiated in Mercury


I am a complete beginner in Mercury language, although I have learned Prolog before. One of the new aspects of Mercury is dererminism. The main function has to be deterministic. In order to make it so, I have to check if a variable is unified/bound to a value, but I cannot find how to do that. Particularly see the code:

main(!IO) :-
mother(X,"john"),
( if bound(X)    <-----this is my failed try; how to check if X is unified?
  then
    io.format("%s\n", [s(X)], !IO)
  else
    io.write_string("Not available\n",!IO)
).

Such main could not fail, i.e. it would (I guess) satisfy the deterministic constraint. So the question is how to check if a variable is bound.


Solution

  • I've translated the family tree from a Prolog example found on this side for comparison. I have specified all facts (persons) and their relationship with each other and a few helper predicates. Note that this typed version did actually find the error that you see in the top answer: female(jane).

    The main predicate does not have to be deterministic, it can also be cc_multi, which means Mercury will commit (not try other) choices it has; you can verify this by replacing mother with parent.

    You also do not have to check for boundness of your variables, instead you just use any not deterministic term in the if clause, and on succeeding the then part will have guaranteed bound variables, or unbound in the else part.

    If you want this example to be more dynamic, you will have to use the lexer or term module to parse input into a person atom.

    If you want all solutions you should check the solution module.

    %-------------------------------%
    % vim: ft=mercury ff=unix ts=4 sw=4 et
    %-------------------------------%
    % File: relationship.m
    %-------------------------------%
    % Classical example of family relationship representation,
    % based on: https://stackoverflow.com/questions/679728/prolog-family-tree
    %-------------------------------%
    
    :- module relationship.
    
    :- interface.
    
    :- import_module io.
    
    %-------------------------------%
    
    :- pred main(io::di, io::uo) is cc_multi.
    
    %-------------------------------%
    %-------------------------------%
    
    :- implementation.
    
    :- type person
        --->    john
        ;       bob
        ;       bill
        ;       ron
        ;       jeff
        ;       mary
        ;       sue
        ;       nancy
        ;       jane
        .
    
    :- pred person(person::out) is multi.
    
    person(Person) :- male(Person).
    person(Person) :- female(Person).
    
    :- pred male(person).
    :- mode male(in) is semidet.
    :- mode male(out) is multi.
    
    male(john).
    male(bob).
    male(bill).
    male(ron).
    male(jeff).
    
    :- pred female(person).
    :- mode female(in) is semidet.
    :- mode female(out) is multi.
    
    female(mary).
    female(sue).
    female(nancy).
    female(jane).
    
    :- pred parent(person, person).
    :- mode parent(in, in) is semidet.
    :- mode parent(in, out) is nondet.
    :- mode parent(out, in) is nondet.
    :- mode parent(out, out) is multi.
    
    parent(mary, sue).
    parent(mary, bill).
    parent(sue, nancy).
    parent(sue, jeff).
    parent(jane, ron).
    
    parent(john, bob).
    parent(john, bill).
    parent(bob, nancy).
    parent(bob, jeff).
    parent(bill, ron).
    
    :- pred mother(person, person).
    :- mode mother(in, in) is semidet.
    :- mode mother(in, out) is nondet.
    :- mode mother(out, in) is nondet.
    :- mode mother(out, out) is nondet.
    
    mother(Mother, Child) :-
        female(Mother),
        parent(Mother, Child).
    
    :- pred father(person, person).
    :- mode father(in, in) is semidet.
    :- mode father(in, out) is nondet.
    :- mode father(out, in) is nondet.
    :- mode father(out, out) is nondet.
    
    father(Father, Child) :-
        male(Father),
        parent(Father, Child).
    
    %-------------------------------%
    
    main(!IO) :-
        Child = john, % try sue or whatever for the first answer
        ( if mother(Mother, Child) then
            io.write(Mother, !IO),
            io.print(" is ", !IO),
            io.write(Child, !IO),
            io.print_line("'s mother", !IO)
        else
            io.write(Child, !IO),
            io.print_line("'s mother is unknown", !IO)
        ).
    
    %-------------------------------%
    :- end_module relationship.
    %-------------------------------%