Если я загляну в вашу программу, я вижу integer(X)
, который лучше заменить на when(nonvar(X), integer(X))
, поскольку в противном случае он не имеет декларативного значения. Поверь мне.
Но теперь, когда у вас есть чистая программа, мы можем найти ошибки благодаря декларативным свойствам Prolog.
Лучше всего спросить Пролог прямо, что он думает:
?- select_integers(Xs, Ys).
Xs = Ys, Ys = [] % expected success
; *loops*
Не так много. Цикл не помогает нам. Он просто говорит, что двигатель Пролога попал в бесконечный цикл, несмотря ни на что. Но мы можем специализировать запрос. Как так:
?- Xs = [_], Ys = [_], select_integers(Xs, Ys).
false. % unexpected failure
Может быть, вы бы предпочли вместо Xs = [1], Ys = [1]
. Я просто попробовал возможный максимум.
Замечание, что мне пришлось ограничивать как Xs
, так и Ys
списку с одним элементом. В противном случае цикл запроса.
Ситуация сейчас намного лучше, поскольку неожиданный сбой означает, что мы можем диагностировать программу. В частности, мы можем обобщить программу, удалив некоторые части.Я нашел это обобщение вашей программы:
:- initialization((Xs = [_], Ys = [_], select_integers(Xs, Ys))).
:- op(950, fy, *).
*_.
select_integers(_/*[]*/,[]).
select_integers([X|XS],L) :-
*when(nonvar(X), integer(X)),
*member(X,L),
select_integers(XS,L).
(Для того, чтобы получить этот фрагмент, я сохранил все в файл, добавил *
некоторые цели и сказал make
неоднократно (который встроен в SWI и есть this module для SICStus), всегда глядя на сообщение об ошибке, цель которого не удалась. Поэтому я старался как можно больше убрать из вашей программы)
Все, что осталось, несет ответственность за сбой. Все остальное не требуется для возникновения сбоя. Это может быть правильно или неправильно, мы не знаем. На самом деле виновником является L
! Если вы посмотрите на правилах чтения его справа налево, он гласит:
условия select_integers(XS,L)
верно, то следующим образом (:-
призвано символизировать стрелок), что select_integers([X|XS], L)
верно.
Другими словами, второй аргумент всегда будет иметь одинаковую длину. И есть только []
! Таким образом, вторым аргументом может быть только пустой список.
select_integers([],[]).
select_integers([X|XS],[X|L]) :-
when(nonvar(X), integer(X)),
select_integers(XS,L).
?- Xs = [_], select_integers(Xs, Ys).
Xs = Ys, Ys = [_A],
when(nonvar(_A), integer(_A)).
% missing further answer
Так что эта программа теперь верна для списков, являющихся целыми числами. Но для списков, которые не являются целыми числами, все равно не получается. Вот краткое исправление для этого:
select_integers([],[]).
select_integers([X|XS],[X|L]) :-
when(nonvar(X), integer(X)),
select_integers(XS,L).
select_integers([X|XS],L) :-
when(nonvar(X), \+integer(X)),
select_integers(XS,L).
?- Xs = [_], select_integers(Xs, Ys).
Xs = Ys, Ys = [_A],
when(nonvar(_A), integer(_A))
; Xs = [_A], Ys = [],
when(nonvar(_A), \+integer(_A)).
Есть более сжатые способы выразить это. Как:
integer_t(X, T) :-
when(nonvar(X), (integer(X) -> T = true ; T = false)).
select_integers(Xs, Is) :-
tfilter(integer_t, Xs, Is).
В системе, которая не поддерживает when/2
(ни freeze/2
) вы можете быть на безопасной стороне с:
integer_t(X, T) :-
functor(X,_,_),
(integer(X) -> T = true ; T = false).
Использование tfilter/3
.
'? - include (integer, YourList, integers) .' – CapelliC
@CapelliC: Неверно получается для' include (integer, [I], []), I = 1.' – false
@false: Я знаю. Но, я думаю, что кто-то, кто * начинает * кодировать в * Prolog *, должен * не * заботиться о. Конечно, это * мое * мнение ... – CapelliC