Как проверить, создается ли переменная в Mercury

78
13

Я полный новичок в языке Меркурия, хотя раньше я изучал Пролог. Одним из новых аспектов Меркурия является деерминизм. 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 не может не подвести итог, т.е. Она (я думаю) удовлетворит детерминированное ограничение. Поэтому вопрос заключается в том, как проверить, связана ли переменная.

спросил(а) 2021-01-25T13:36:23+03:00 4 месяца, 3 недели назад
1
Решение
63

Я перевел генеалогическое дерево из примера Prolog, найденного на этой стороне для сравнения. Я указал все факты (личности) и их отношения друг с другом и несколько вспомогательных предикатов. Обратите внимание, что эта типизированная версия действительно нашла ошибку, которую вы видите в верхнем ответе: female(jane).

Основной предикат не обязательно должен быть детерминированным, он также может быть cc_multi, что означает, что Меркурий будет совершать (не попробовать другие) варианты, которые он имеет; вы можете проверить это, заменив mother parent.

Вам также не нужно проверять ограниченность ваших переменных, вместо этого вы просто используете какой-либо не детерминированный термин в предложении if, а при выполнении последующей части будут иметь гарантированные связанные переменные или несвязанные в части else.

Если вы хотите, чтобы этот пример был более динамичным, вам нужно будет использовать модуль lexer или term для синтаксического анализа ввода в person атом.

Если вам нужны все решения, вы должны проверить модуль solution.

%-------------------------------%
% vim: ft=mercury ff=unix ts=4 sw=4 et
%-------------------------------%
% File: relationship.m
%-------------------------------%
% Classical example of family relationship representation,
% based on: /questions/635608/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(" mother", !IO)
else
io.write(Child, !IO),
io.print_line(" mother is unknown", !IO)
).

%-------------------------------%
:- end_module relationship.
%-------------------------------%

ответил(а) 2021-01-25T13:36:23+03:00 4 месяца, 3 недели назад
63

Вам не нужно проверять переменные для их состояния экземпляра. Я никогда не делал этого почти за 10 лет использования Меркурия на ежедневной основе. Для каждого предикатного и предикатного режимов Меркурий знает статически инстанцирование каждой переменной в каждой точке программы. Поэтому, используя ваш пример:

% 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 уже заземлен), потому что может быть правдой только одна дизъюнкция. поэтому он дает только один ответ.

Если эта статическая грубость может стать сложной, это когда у вас многомодовый предикат. Меркурию, возможно, потребуется переупорядочить ваши союзы, чтобы сделать программный режим правильным: например, использовать переменную после ее производства. Тем не менее, использование и состояние экземпляров переменных всегда будут статически известны.

Я понимаю, что это действительно сильно отличается от Prolog и может потребовать значительного количества unlearning.

Надеюсь, это поможет, все лучшее.

ответил(а) 2021-01-25T13:36:23+03:00 4 месяца, 3 недели назад
45

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

Если mother детерминирована (det) в этом режиме, она всегда дает вам одно значение для X В этом случае нет необходимости проверять что-либо; mother(X, "john") дает вам мать Джона, конец истории, поэтому нет необходимости в "Недоступном случае".

Поскольку вы пытаетесь писать дела, чтобы справиться с ними, когда mother дает вам что-то, а когда нет, я предполагаю, что mother не детерминирована. Если он semidet то есть две возможности; он преуспевает, когда X привязан к чему-то, или он терпит неудачу. Это не удастся с X unbound.

Ваш код ничего не говорит о том, как main (которая всегда требуется для успеха) может преуспеть, если mother терпит неудачу. Помните, что запятая является логической связью (и). В вашем коде говорится, что " main преуспевает, если mother(X, "john") преуспевает AND (if.. then... else...) succeeds ". Но если mother терпит неудачу, то что? По этой причине компилятор отклонил ваш код, даже если остальная часть вашего кода была действительна.

Но конструкция if... then... else... точно спроектирована таким образом, чтобы вы могли проверить цель, которая может быть успешной или неудачной, и указать случай, когда цель будет успешной, и случай, когда она терпит неудачу, так что целое if/then/else всегда преуспевает. Итак, все, что вам нужно сделать, это поместить mother(X, "john") в состояние if/then/else.

В Mercury вы не включаете переменные, которые либо связаны, либо не связаны. Вместо этого просто проверьте, не удалась ли цель, которая могла бы связать переменную.

ответил(а) 2021-01-25T13:36:23+03:00 4 месяца, 3 недели назад
Ваш ответ
Введите минимум 50 символов
Чтобы , пожалуйста,
Выберите тему жалобы:

Другая проблема