简体   繁体   English

如何检查变量是否在 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.我是 Mercury 语言的完全初学者,虽然我之前学习过 Prolog。 One of the new aspects of Mercury is dererminism.水星的新方面之一是真皮主义。 The main function has to be deterministic. main函数必须是确定性的。 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, ie it would (I guess) satisfy the deterministic constraint.这样的main不会失败,即它会(我猜)满足确定性约束。 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.我已经从这边找到的Prolog 示例中翻译了家谱以进行比较。 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).请注意,此键入版本确实找到了您在最佳答案中看到的错误: 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;主谓不必是确定性的,也可以是cc_multi ,这意味着水星将提交(不试试其他)选择它; you can verify this by replacing mother with parent .你可以通过用parent替换mother来验证这一点。

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 子句中使用任何非确定性术语,并且在成功之后 then 部分将有保证的绑定变量,或者在 else 部分中未绑定。

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.如果你想让这个例子更加动态,你将不得不使用lexerterm模块将输入解析为一个person原子。

If you want all solutions you should check the solution module.如果您想要所有解决方案,您应该检查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.
%-------------------------------%

You do not need to check variables for their instantiation state.您不需要检查变量的实例化状态。 I have never done it in almost 10 years of using Mercury on a daily basis.在几乎每天使用 Mercury 的近 10 年中,我从未这样做过。 For each predicate and predicate's mode, Mercury knows statically the instantiation of each variable at each point in the program.对于每个谓词和谓词的模式,Mercury静态地知道程序中每个点的每个变量的实例化。 So using your example:所以使用你的例子:

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

The declaration for mother says that its first argument is an output argument, this means that after the call to mother its value will be ground. Mother 的声明说它的第一个参数是一个输出参数,这意味着在调用 Mother 之后它的值将被接地。 and so it can be printed.所以它可以被打印出来。 If you did use a var predicate (and there is one in the standard library) it would always fail.如果您确实使用了 var 谓词(并且标准库中有一个),它总是会失败。

To do this Mercury places other requirements on the programmer.为此,Mercury 对程序员提出了其他要求。 For example.例如。

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

The above code is illegal.上面的代码是非法的。 Because Y is produced in the first case, but not in the second so it's groundness is not well defined.因为 Y 是在第一种情况下产生的,但不是在第二种情况下产生的,所以它的基础没有明确定义。 The compiler also knows that the disjunction is a switch (when X is already ground) because only one disjunct can possibly be true.编译器也知道析取是一个开关(当 X 已经接地时),因为只有一个析取可能是真的。 so there it produces only one answer.所以它只产生一个答案。

Where this static groundness can become tricky is when you have a multi-moded predicate.当您有一个多模式谓词时,这种静态基础会变得棘手。 Mercury may need to re-order your conjunctions to make the program mode correct: eg to put a use of a variable after it's production. Mercury 可能需要重新排列您的连词以使程序模式正确:例如,在变量生成后使用它。 Nevertheless the uses and instantiation states of variables will always be statically known.尽管如此,变量的使用和实例化状态将始终是静态已知的。

I understand this is really quite different from Prolog, and may require a fair amount of unlearning.我知道这与 Prolog 真的很不一样,可能需要大量的学习。

Hope this helps, all the best.希望这会有所帮助,一切顺利。

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

This code doesn't make a lot of sense in Mercury.这段代码在 Mercury 中没有多大意义。 If X is a standard output variable from mother , it will never succeed with X unbound.如果X是来自mother的标准输出变量,则它永远不会在X未绑定的情况下成功。

If mother is deterministic ( det ) in this mode, it will always give you a single value for X .如果在这种模式下mother是确定性的 ( det ),它将始终为您提供X的单个值。 In that case there would be no need to check anything;在那种情况下,不需要检查任何东西; mother(X, "john") gives you John's mother, end of story, so there's no need for the "Not available case". mother(X, "john")给你约翰的母亲,故事的结尾,所以不需要“不可用的情况”。

Since you're trying to write cases to handle both when mother gives you something and when it doesn't, I'm assuming mother is not deterministic.由于您正在尝试编写案例来处理mother给您和不给您的情况,因此我假设mother不是确定性的。 If it's semidet then there are two possibilities;如果是semidet那么有两种可能性; it succeeds with X bound to something, or it fails .它在X绑定到某物时成功,或者失败 It will not succeed with X unbound. X未绑定将不会成功。

Your code doesn't say anything about how main (which is required to always succeed) can succeed if mother fails.如果mother失败,您的代码没有说明main (必须始终成功)如何成功。 Remember that the comma is logical conjunction (and).请记住,逗号是逻辑连词(和)。 Your code says " main succeeds if mother(X, "john") succeeds AND ( if .. then ... else ...) succeeds ".您的代码表示,“ main成功,如果mother(X, "john")成功,( if .. then ... else ...) succeeds ”。 But if mother fails , then what?但如果mother失败了,那又如何呢? The compiler would reject your code for this reason, even if the rest of your code was valid.编译器会因为这个原因拒绝你的代码,即使你的代码的其余部分是有效的。

But the if ... then ... else ... construct is exactly designed to allow you to check a goal that may succeed or fail, and specify a case for when the goal succeeds and a case for when it fails, such that the whole if/then/else always succeeds.但是if ... then ... else ...构造完全被设计为允许您检查可能成功或失败的目标,并指定目标成功时的情况和失败时的情况,例如整个 if/then/else总是成功。 So all you need to do is put mother(X, "john") in the condition of the if/then/else.所以你需要做的就是把mother(X, "john")放在if/then/else 的条件中。

In Mercury you don't switch on variables that are either bound or unbound.在 Mercury 中,您不会打开绑定或未绑定的变量。 Instead just check whether the goal that might have bound the variable succeeded or failed.相反,只需检查可能绑定变量的目标是成功还是失败。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM