Предикат, который генерирует целые числа и проверяет, является ли целое число
Я пытаюсь создать предикат Prolog, который позволит мне проверить, является ли заданное значение целым числом больше 0, а также даст мне допустимое целое число с учетом переменной. Теперь это выглядит так:
intgr(1).
intgr(X) :- intgr(Y), X is Y+1.
Это сгенерирует все целые числа, но при использовании в качестве intgr(8) он обнаружит, что оно допустимо, а затем зациклится навсегда. Есть идеи, как это решить?
2 ответа
Для генерации натуральных чисел вы можете легко написать хвост-рекурсивный (и, следовательно, более экономичный) предикат. Например:
next_integer(I) :-
next_integer(1, I).
next_integer(I, I).
next_integer(I, J) :-
I2 is I + 1,
next_integer(I2, J).
Но обратите внимание, что несколько компиляторов Prolog уже предоставили, либо как встроенный предикат, либо как предикат библиотеки, стандарт де-факто between/3
Предикат, который позволяет перечислять целые числа в заданном интервале. Например:
?- between(1, 3, I).
I = 1 ;
I = 2 ;
I = 3.
В зависимости от реализации, вы также можете использовать этот предикат для проверки, принадлежит ли целое число заданному интервалу, не оставляя ложных точек выбора. Например:
?- between(1, 3, 2).
true.
Возвращаясь к вашему вопросу, ваш предикат будет зацикливаться на обратном отслеживании при тестировании, так как в нем нет ничего, что говорит о том, что передаваемый вами аргумент не будет найден снова, если вы продолжите добавлять его на каждом проходе. Одним из решений будет проверка аргумента с использованием стандартного встроенного предиката var/1
и вырезать первое решение, когда аргумент связан. Например:
next_integer(I) :-
( var(I) ->
next_integer(1, I).
; integer(I) ->
next_integer(1, I),
!
; fail % or error
)
next_integer(I, I).
next_integer(I, J) :-
I2 is I + 1,
next_integer(I2, J).
Надеюсь это поможет.
Вот первая причина, почему ваша программа не завершается. Чтобы увидеть это, я добавлю цели false
в вашу программу:
intgr (1): - неверно. intgr (X): - intgr (Y), false,X - Y + 1.
Что сейчас интересно, так это следующее свойство. Учитывая любой запрос для вашей программы,
Если этот фрагмент (fail-slice) не завершается, то и исходная программа не прерывается.
В этом фрагменте, вероятно, легче увидеть: нет способа, которым эта программа может завершиться. Переменная X
происходит только один раз в голове. В видимой части программы нет дальнейших ссылок, и, таким образом, никто не заботится о конкретной реализации X
, То есть: независимо от того, что вы указали в качестве аргумента intgr/1
Ваше определение будет зациклено. Что-нибудь! intgr(-1)
петли, intgr(stop)
петли, intgr(X)
петли, intgr(1)
петли.
Для получения дополнительной информации об ошибках-срезах и их использовании см. Тег fail-slice.
Чтобы устранить проблему, нужно что-то изменить в видимой части вашей программы. Не смотрите на зачеркнутые участки - они не смогут улучшить завершение.
я хотел бы использовать length(_, N)
который включает в себя 0. Вот еще один способ использования library(clpfd)
:
?- X #> 0.
И если вы настаиваете на перечислении решений:
nat(0).
nat(X0) :-
X0 #> 0,
X1 #= X0-1,
nat(X1).