2

我是 Mercury 语言的完全初学者,虽然我之前学过 Prolog。水星的新方面之一是去毛病。main函数必须是确定性的。为了做到这一点,我必须检查一个变量是否统一/绑定到一个值,但我找不到如何做到这一点。特别看代码:

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

这样main不会失败,即(我猜)它会满足确定性约束。所以问题是如何检查变量是否被绑定。

4

3 回答 3

2

我已经从这边找到的Prolog 示例翻译了家谱以进行比较。我已经指定了所有事实(人)及其彼此之间的关系以及一些辅助谓词。请注意,此键入的版本实际上确实找到了您在最佳答案中看到的错误:female(jane).

主谓词不一定确定性的,也可以是cc_multi,这意味着 Mercury 将提交(而不是尝试其他)它拥有的选择;您可以通过替换来验证这mother一点parent

您也不必检查变量的边界,而只需在 if 子句中使用任何非确定性术语,并且在成功时 then 部分将有保证的绑定变量,或者在 else 部分中未绑定。

如果您希望此示例更加动态,则必须使用lexerorterm模块将输入解析为person原子。

如果您想要所有解决方案,您应该检查solution模块。

%-------------------------------%
% 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.
%-------------------------------%
于 2016-10-16T08:24:15.450 回答
1

您不需要检查变量的实例化状态。在每天使用 Mercury 的近 10 年里,我从未这样做过。对于每个谓词和谓词的模式,Mercury静态地知道程序中每个点的每个变量的实例化。所以使用你的例子:

% I'm making some assumptions here.
:- pred mother(string::out, string::in) is det.

main(!IO) :-
    mother(X,"john"),
    io.format("%s\n", [s(X)], !IO).

母亲的声明说它的第一个参数是一个输出参数,这意味着在调用母亲之后,它的价值将被接地。这样就可以打印了。如果您确实使用了 var 谓词(标准库中有一个),它总是会失败。

为此,Mercury 对程序员提出了其他要求。例如。

(
    X = a,
    Y = b
;
    X = c
)
io.write(Y, !IO)

上面的代码是非法的。因为 Y 是在第一种情况下产生的,但不是在第二种情况下产生的,所以它的接地性没有很好的定义。编译器还知道析取是一个开关(当 X 已经接地时),因为只有一个析取可能为真。所以它只产生一个答案。

当你有一个多模态谓词时,这种静态基础可能会变得棘手。Mercury 可能需要重新排序您的连词以使程序模式正确:例如,在变量产生后使用它。尽管如此,变量的使用和实例化状态总是静态已知的。

我知道这与 Prolog 完全不同,可能需要大量的学习。

希望这会有所帮助,一切顺利。

于 2016-10-16T22:12:13.313 回答
0
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)
  ).

这段代码在 Mercury 中没有多大意义。如果X是来自 的标准输出变量mother,它永远不会在X未绑定的情况下成功。

如果在此模式下mother是确定性的 ( det),它将始终为您提供X. 在这种情况下,不需要检查任何东西;mother(X, "john")给你约翰的母亲,故事的结尾,所以不需要“不可用的情况”。

由于您正在尝试编写案例来处理何时mother给您某些东西和何时不给您某些东西,所以我假设mother这不是确定性的。如果是,semidet那么有两种可能性;它成功X绑定到某事,或者失败。未绑定不会成功X

如果失败,您的代码没有说明如何main(始终成功)如何成功。mother请记住,逗号是逻辑连词 (and)。您的代码说“main如果mother(X, "john")成功 AND ( if .. then ... else ...) succeeds”则成功。但如果mother 失败,那又怎样?编译器会因此拒绝您的代码,即使您的其余代码是有效的。

但是该if ... then ... else ...结构的设计目的是允许您检查可能成功或失败的目标,并指定目标成功时的情况和失败时的情况,这样整个 if/then/else总是成功。因此,您需要做的就是置于if/then/elsemother(X, "john")条件下。

在 Mercury 中,您不会打开已绑定或未绑定的变量。相反,只需检查可能绑定变量的目标是成功还是失败。

于 2017-01-26T22:58:14.650 回答