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.
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.
%-------------------------------%