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

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

3 ответа

Решение

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

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

Вам также не нужно проверять привязку ваших переменных, вместо этого вы просто используете какой-либо недетерминированный термин в предложении if, и при последующем выполнении часть then будет иметь гарантированные связанные переменные или не связана в части 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: https://stackru.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.
%-------------------------------%

Вам не нужно проверять переменные на предмет их состояния. Я никогда не делал этого почти за 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).

Объявление для mother говорит, что его первый аргумент является выходным аргументом, это означает, что после вызова mother его значение будет заземлено. и так его можно распечатать. Если бы вы использовали предикат var (а в стандартной библиотеке он есть), он всегда потерпит неудачу.

Для этого Mercury предъявляет другие требования к программисту. Например.

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

Код выше является незаконным. Потому что Y производится в первом случае, но не во втором, поэтому его обоснованность не очень хорошо определена. Компилятор также знает, что дизъюнкция является переключателем (когда X уже заземлен), потому что только один дизъюнкт может быть истинным. так что там он дает только один ответ.

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

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

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

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

Этот код не имеет большого смысла в Меркурии. Если X стандартная выходная переменная из motherникогда не преуспеет с X несвязанный.

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

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

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

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

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

Другие вопросы по тегам