«если» в прологе? - PullRequest
       33

«если» в прологе?

50 голосов
/ 17 мая 2010

Есть ли способ сделать if в прологе, например, если переменная равна 0, то выполнить некоторые действия (записать текст в терминал). Иное даже не нужно, но я не могу найти документацию, если.

Ответы [ 10 ]

85 голосов
/ 11 июня 2011

Да, в ISO Prolog существует такая управляющая конструкция, которая называется ->. Вы используете это так:

( condition -> then_clause ; else_clause )

Вот пример, в котором используется цепочка предложений else-if:

(   X < 0 ->
    writeln('X is negative.  That's weird!  Failing now.'),
    fail
;   X =:= 0 ->
    writeln('X is zero.')
;   writeln('X is positive.')
)

Обратите внимание, что если вы опустите предложение else, условие сбой будет означать, что весь оператор if потерпит неудачу. Поэтому я рекомендую всегда включать условие else (даже если оно просто true).

49 голосов
/ 17 мая 2010

Стандартный предикат пролога сделает это.

   isfive(5). 

будет иметь значение true, если вы вызовете его с 5 и потерпите неудачу (вернете false), если вы запустите его с чем-то еще. Для не равных вы используете \ =

isNotEqual(A,B):- A\=B.

Технически это не унифицирует, но похоже на не равное.

Learn Prolog Now - хороший сайт для изучения пролога.

Edit: Добавить еще один пример.

isEqual(A,A). 
25 голосов
/ 10 декабря 2011

Пролог предикатов 'унифицировать' -

Итак, в императивном языке я бы написал

function bazoo(integer foo)
{
   if(foo == 5)
       doSomething();
   else
       doSomeOtherThing();
}

В Прологе я бы написал

bazoo(5) :-  doSomething.
bazoo(Foo) :- Foo =/= 5, doSomeOtherThing.

что, когда вы понимаете оба стиля, на самом деле намного понятнее.
«Я базу для особого случая, когда foo 5»
«Я нормальный случай, когда foo не 5»

11 голосов
/ 07 декабря 2012

Я нашел это полезным для использования оператора if в правиле.

max(X,Y,Z) :-
    (  X =< Y
    -> Z = Y
    ;  Z = X
    ).

Благодаря http://cs.union.edu/~striegnk/learn-prolog-now/html/node89.html

9 голосов
/ 16 октября 2015

Во-первых, давайте вспомним классическую логику первого порядка:

" Если P , то Q else R" эквивалентно "(P и Q) или (non_P и R) ".


Как мы можем выразить «если-то-еще» как , что в Прологе?

Давайте рассмотрим следующий конкретный пример:

Если X является членом списка [1,2] , тогда X равно 2 иначе X равно 4.

Мы можем сопоставить вышеуказанный шаблон (" Если P , то Q else R"), если ...

  • состояние P равно list_member([1,2],X),
  • отрицательное условие non_P - non_member([1,2],X),
  • следствие Q равно X=2 и
  • альтернатива R - это X=4.

Чтобы выразить список (не) членство в чистом виде, мы определяем:

list_memberd([E|Es],X) :-
   (  E = X
   ;  dif(E,X),
      list_memberd(Es,X)
   ).

non_member(Es,X) :-
   maplist(dif(X),Es).

Давайте рассмотрим различные способы выражения «если-то-еще» в прологе!

  1. (P,Q ; non_P,R)

    ?-      (list_memberd([1,2],X), X=2 ; non_member([1,2],X), X=4).
    X = 2 ; X = 4.
    ?- X=2, (list_memberd([1,2],X), X=2 ; non_member([1,2],X), X=4), X=2.
    X = 2 <i>; false</i>.
    ?-      (list_memberd([1,2],X), X=2 ; non_member([1,2],X), X=4), X=2.
    X = 2 <i>; false</i>.
    ?- X=4, (list_memberd([1,2],X), X=2 ; non_member([1,2],X), X=4), X=4.
    X = 4.
    ?-      (list_memberd([1,2],X), X=2 ; non_member([1,2],X), X=4), X=4.
    X = 4.
    

    Оценка правильности 5/5. Оценка эффективности 3 / 5.

  2. (P -> Q ; R)

    ?-      (list_memberd([1,2],X) -> X=2 ; X=4).
    <b>false</b>.                                                % WRONG
    ?- X=2, (list_memberd([1,2],X) -> X=2 ; X=4), X=2.
    X = 2.
    ?-      (list_memberd([1,2],X) -> X=2 ; X=4), X=2.
    <b>false</b>.                                                % WRONG
    ?- X=4, (list_memberd([1,2],X) -> X=2 ; X=4), X=4.
    X = 4.
    ?-      (list_memberd([1,2],X) -> X=2 ; X=4), X=4.
    <b>false</b>.                                                % WRONG
    

    Оценка правильности 2/5. Оценка эффективности 2 / 5.

  3. (P *-> Q ; R)

    ?-      (list_memberd([1,2],X) *-> X=2 ; X=4).
    X = 2 <b>; false</b>.                                        % WRONG
    ?- X=2, (list_memberd([1,2],X) *-> X=2 ; X=4), X=2.
    X = 2 <i>; false</i>.
    ?-      (list_memberd([1,2],X) *-> X=2 ; X=4), X=2.
    X = 2 <i>; false</i>.
    ?- X=4, (list_memberd([1,2],X) *-> X=2 ; X=4), X=4.
    X = 4.
    ?-      (list_memberd([1,2],X) *-> X=2 ; X=4), X=4.
    <b>false</b>.                                                % WRONG
    

    Оценка правильности 3/5. Оценка эффективности 1 / 5.


(Предварительно) резюме:

  1. (P,Q ; non_P,R) правильно, но нуждается в дискретной реализации non_P.

  2. (P -> Q ; R) теряет декларативную семантику при недостаточной реализации.

  3. (P *-> Q ; R) "менее" неполно, чем (P -> Q ; R), но все еще имеет подобные проблемы.


К счастью для нас, есть альтернативы: Введите логически монотонную управляющую конструкцию if_/3!

Мы можем использовать if_/3 вместе с уточненным предикатом членства в списке memberd_t/3 примерно так:

?-      if_(memberd_t(X,[1,2]), X=2, X=4).
X = 2 ; X = 4.
?- X=2, if_(memberd_t(X,[1,2]), X=2, X=4), X=2.
X = 2.
?-      if_(memberd_t(X,[1,2]), X=2, X=4), X=2.
X = 2 <i>; false</i>.
?- X=4, if_(memberd_t(X,[1,2]), X=2, X=4), X=4.
X = 4.
?-      if_(memberd_t(X,[1,2]), X=2, X=4), X=4.
X = 4.

Оценка правильности 5/5. Оценка эффективности 4 / 5.

5 голосов
/ 05 мая 2016

Существуют три различных способа выражения чего-то вроде if-then-else в Прологе. Для сравнения рассмотрим char_class/2. Для a и b класс должен быть ab и other для всех других терминов. Можно написать это неуклюже так:

char_class(a, ab).
char_class(b, ab).
char_class(X, other) :-
   dif(X, a),
   dif(X, b).

?- char_class(Ch, Class).
   Ch = a, Class = ab
;  Ch = b, Class = ab
;  Class = other,
   dif(Ch, a), dif(Ch, b).

Чтобы написать вещи более компактно, необходима конструкция if-then-else. Пролог имеет встроенный:

?- ( ( Ch = a ; Ch = b ) -> Class = ab ; Class = other ).
   Ch = a, Class = ab.

Хотя этот ответ звучит здраво, он неполон. Только первый ответ от ( Ch = a ; Ch = b ) дается. Другие ответы отрублены. Действительно, не очень реляционный.

Лучшая конструкция, часто называемая «мягким срезом» (не верьте названию, «срез - это срез»), дает несколько лучшие результаты (это в YAP):

?- ( ( Ch = a ; Ch = b ) *-> Class = ab ; Class = other ).
   Ch = a, Class = ab
;  Ch = b, Class = ab.

В качестве альтернативы, SICStus имеет if/3 с очень похожей семантикой:

?- if( ( Ch = a ; Ch = b ), Class = ab , Class = other ).
   Ch = a, Class = ab
;  Ch = b, Class = ab.

Таким образом, последний ответ все еще скрыт. Теперь введите library(reif) для SICStus , YAP и SWI . Установите его и скажите:

?- use_module(library(reif)).

?- if_( ( Ch = a ; Ch = b ), Class = ab , Class = other ).
   Ch = a, Class = ab
;  Ch = b, Class = ab
;  Class = other,
   dif(Ch, a), dif(Ch, b).

Обратите внимание, что все if_/3 скомпилированы в дико вложенный if-then-else для

char_class(Ch, Class) :-
   if_( ( Ch = a ; Ch = b ), Class = ab , Class = other ).

, который расширяется в YAP 6.3.4 до:

char_class(A,B) :-
   ( A\=a
   ->
     ( A\=b
     ->
       B=other
     ;
       ( A==b
       ->
         B=ab
       )
     ;
       A=b,
       B=ab
     ;
       dif(A,b),
       B=other
     )
   ;
     ( A==a
     ->
       B=ab
     )
   ;
     A=a,
     B=ab
   ;
     dif(A,a),
     ( A\=b
     ->
       B=other
     ;
       ( A==b
       ->
         B=ab
       )
     ;
       A=b,
       B=ab
     ;
       dif(A,b),
       B=other
     )
   ).
5 голосов
/ 11 октября 2013

Лучше всего использовать так называемый cuts, который имеет символ !.

if_then_else(Condition, Action1, Action2) :- Condition, !, Action1.  
if_then_else(Condition, Action1, Action2) :- Action2.

Выше приведена базовая структура функции условия.

Для примера вот функция max:

max(X,Y,X):-X>Y,!.  
max(X,Y,Y):-Y=<X.

Я предлагаю прочитать больше документации по срезам, но в целом они похожи на точки останова. Пример: в случае, если первая функция max возвращает истинное значение, вторая функция не проверяется.

PS: я довольно новичок в Прологе, но это то, что я узнал.

4 голосов
/ 17 мая 2010

Программа Prolog на самом деле является большим условием для «если» с «тогда», которое печатает «Цель достигнута» и «еще», которое печатает «Близкие не найдены». A, B означает «A истинно, а B истинно», большинство систем прологов не будет пытаться удовлетворить «B», если «A» не достижимо (то есть X=3, write('X is 3'),nl выведет «X равно 3», когда X = 3, и ничего не будет делать, если X = 2).

2 голосов
/ 08 июля 2014
(  A == B ->
     writeln("ok")
;
     writeln("nok")
),

Требуется остальная часть

1 голос
/ 05 декабря 2016

Вы должны прочитать Изучите Пролог сейчас! Глава 10.2 Использование Cut . Это дает пример:

max(X,Y,Z) :- X =< Y,!, Y = Z.

будет сказано,

Z равно Y IF ! верно (что всегда) AND X равно <= Y.

...