2015-02-11 3 views
1

Так что я столкнулся с проблемой с моей проблемой Prolog. допустим, вы спросите это:Застрял с программой пролога

?-num(100,200). 

Программа должна возвращать все числа из этого интервала, который может генерировать номер 6 из theosophique сокращения (123 = 1 + 2 + 3 = 6, так что я должен вернуть 123, 105 = 1 + 0 + 5 = 6, поэтому я тоже должен вернуть его. У меня уже есть программа, которая будет выполнять вычисления для этого. У меня есть что-то, и я уверен, что я должен работать, но он действительно даже работает. до сих пор редукт работает отлично

num(X,Y):- 
    repeat, 
    reduct(X,T), 
    T=:=6 ->write(X), 
    X is X+1, 
    (X=:=Y),!. 
+0

кто-нибудь пожалуйста ??? –

+1

* У меня есть что-то, и я уверен, что я должен работать, но он действительно даже работает * Это звучит немного как противоречие, не так ли? ;) Можете ли вы уточнить, что «даже не запускается»? Вы получили сообщение об ошибке? И вы написали код для 'reduct'? Кроме того, оператор '=: =' определяет, являются ли два арифметических выражения равными при оценке. Кажется, вы пытаетесь использовать его как оператор присваивания, который не будет работать. Пролог не выполняет задания. Он делает * унификации *. 'X is X + 1' всегда будет терпеть неудачу в Prolog, потому что значение' X' никогда не будет равно «X + 1». – lurker

+0

Я изменил его, но он падает так же, как и раньше –

ответ

1

есть немного, чтобы добавить комментарии ценного Lurker»...

Где он предлагает

Возможно, вы пытаетесь использовать его в качестве оператора присваивания, который не будет работать. Пролог не выполняет задания. Это унификации.

Вы должны сделать некоторые выводы о петлях. Ваш код не может работать, потому что ему не хватает «генерировать» часть «сгенерировать-и-тест», которую вы закодировали в цикле, вызванном сбоем.

Итак, добавьте генератор, например, между/3 или используйте рекурсию, вместо цикла с отключенным приводом.

Это 1 лайнер, который может помочь вам выполнить ваше задание.

?- [user]. 
|: num(X,Y) :- between(X,Y,N), number_codes(N,Cs), aggregate(sum(D),C^(member(C,Cs),D is C-0'0),6), writeln(N). 

?- num(100,200). 
105 
true ; 
114 
true ; 
123 
true ; 
132 
true ; 
141 
true ; 
150 
true ; 
false. 
2

В дополнении к рекомендации CapelliC на использование between/3 (который идеально подходит для итерации диапазона целых чисел в данном случае), давайте сломаем существующий предикат, чтобы увидеть, что это не так.

Помнить оператора старшинства

The '' выше, чем ->. Таким образом, ваш предикат ведет себя так:

num(X,Y):- 
    repeat, 
    reduct(X,T), 
    T=:=6 -> 
    ( write(X), 
     X is X+1, 
     (X=:=Y), ! 
    ). 

Как только T =:= 6 не удается, у вас есть бесконечный цикл через, repeat, reduct(X, T), T =:= 6 так X никогда не изменится, и, следовательно, T никогда не меняется, и поэтому T =:= 6 продолжает терпеть неудачу и Пролог backtracks - repeat. Таким образом, в вашем коде это бесконечный цикл.

Ваша стратегия использования repeat и разреза (!) не будет работать здесь

В форме, что у вас есть:

repeat, 
<do some queries>, 
X =:= Y, % succeed if X and Y have the same value 
! 

repeat всегда удается. В любое время, когда Prolog возвращается назад до repeat, он снова будет двигаться вперед, ища больше решений. Сокращение говорит Prolog не возвращаться к этой точке (точка разреза).Проблема здесь в том, что X, который уже был создан (до 100) в начале запроса на вызов num(100, 200), никогда не может иметь то же значение, что и Y, которое установлено в 200 (см. Ниже). Таким образом, X =:= Y всегда будет терпеть неудачу.

Внутри пункта предиката Prolog, переменная не может быть изменена только через возвратов и Воссоединения

При запросе, num(100, 200), с самого начала X и Y были экземпляры с 100 и 200, соответственно. В этот момент значения X и Y теперь могут никогда не изменить во время выполнения этого предикатного предложения. Выражение X is X + 1 будет всегда сбой, потому что Prolog будет оценивать X + 1 и определить, -X, что никогда не может быть правдой (в этом случае он всегда будет сравнивать 100 с 101).

При запросе предикат в Прологе, скажем foo(A, B), он стремится найти значения для всех переменных, которые не были установлены уже (они uninstantiated), которые делают запрос, истинный. Если он находит такие значения, он преуспевает. Если он не может найти, он терпит неудачу. Если у вас есть серия запросов, разделенных конъюнкцией (,), скажем, foo1(A), foo2(A), Prolog сначала запрашивает foo1(A) и, если он преуспеет, запросит foo2(A). Если foo2(A) терпит неудачу, Prolog будет backtrack до foo1(A) и попытаться сделать это с другим значением A *, если A был unininstiated (не установлен) до foo1(A).

Перебор целочисленного диапазона

В вашем назначении, вам нужно перебирать от одного целого к другому (от X к Y в num(X, Y) запросе). Как это можно сделать с ограничением, что вы не можете повторно назначить переменную в Prolog без обратного отслеживания? В Prolog существует несколько способов сделать это. Одним из чистых способов является метод CapelliC с использованием between/3.

num(X, Y) :- 
    % `between` will first instantiate N with X. 
    % On backtracking, it will instantiate N with successive values 
    % and succeed until the value exceeds Y. Then it will fail. 
    % 
    between(X, Y, N), 
    <do some calls with N, write out successful values>, 
    fail.     % Automatically backtrack here 

Другой способ рекурсивно:

num(X, Y) :- 
    % NOTE: if X and Y are given, then their values CANNOT BE CHANGED 
    % in this predicate clause! 
    % 
    X =< Y,    % num(X, Y) succeeds only if X =< Y 
    <do some calls with X and/or Y, write successful values>, 
    NextX is X + 1,  % New variable whose value is X + 1 
    num(NextX, Y). 

рекурсия будет продолжаться до тех пор, num не видит X идти больше, чем Y и, наконец, не в состоянии.

Пролог «если-иначе» построить

Если вы хотите сделать if конструкцию, вы должны скобки взять оператор приоритет во внимание:

( <test> 
-> <something 1>,   % if test succeeds 
    ... 
    <something N> 
; <something else 1>, 
    ... 
    <something else M> 
) 

Если вы просто хотите добиться успеха на «остальное» дело и не делать «что-то другое», просто сделать true:

( <test> 
-> <something 1>,   % if test succeeds 
    ... 
    <something N> 
; true 
) 

В приведенных выше примерах по-прежнему используется ваш write метод отображения результатов для пользователя. На самом деле это не канонический способ сделать это в Prolog. Лучше было бы определить предикат, скажем, num(X, Y, R), который будет последовательно предоставлять значения R, которые делают его истинным, когда он отступает. Это незначительные изменения в вышеуказанных случаях:

num(X, Y, R) :- 
    % `between` will first instantiate N with X. 
    % On backtracking, it will instantiate N with successive values 
    % and succeed until the value exceeds Y. Then it will fail. 
    % 
    between(X, Y, R), 
    <do some calls with R>. % Succeed if R passes criteria 

Или

num(X, Y, X) :- 
    % NOTE: if X and Y are given, then their values CANNOT BE CHANGED 
    % in this predicate clause! 
    % 
    X =< Y,    % num(X, Y) succeeds only if X =< Y 
    <do some calls with X and/or Y>. % Succeed if X passes criteria 
num(X, Y, R) :- 
    X < Y, 
    X1 is X + 1, 
    num(X1, Y, R). 

Затем каждый отступаться производит каждый результат:

?- num(100,200,R). 
R = 105 ; 
R = 114 ; 
... 
false. 
+0

теперь это объяснение! Я (много) зависть к вашей беглости ... – CapelliC

+0

WOw спасибо за это объяснение! У меня наконец-то это работает !! любые советы по освоению этого языка? Я действительно сосать его (как и другие парадигмы), но мне очень нравится вызов хорошо на вещах, которые я нахожу очень трудными .. как рекурсия –

+0

CapelliC, спасибо также за вашего анвера –

Смежные вопросы