Пролог: итерация

Добрый вечер, у меня простая проблема, и я предупреждаю вас, что я очень новичок в прологе. Предположим, что у вас есть три списка одинакового размера, каждый из которых содержит только 1, 0 или -1. Я хочу убедиться, что для всех i из i-х элементов трех списков один и только один не равен нулю.

Этот код делает это для фиксированного i:

:- use_module(library(clpfd)).

compat1(V1,V2,V3,I) :-
    length(V1,G),
    nth1(I,V1,X),
    nth1(I,V2,Y),
    nth1(I,V3,Z),
    W is X*X+Y*Y+Z*Z,
    W is 1,
    I in 1..G.

как я могу сказать «для ВСЕХ I, compat1 (V1, V2, V3, I)»? я пытался определить

compat2(V1,V2,V3,1) :- compat1(V1,V2,V3,1).
compat2(V1,V2,V3,K) :- compat2(V1,V2,V3,J), compat1(V1,V2,V3,K), K is J+1.

чтобы я мог вызвать его с K = максимальное значение, которое меня интересует. Но compat2 не работает: дает true, затем после ";" работает бесконечно.

Спасибо!


person Martino    schedule 22.08.2011    source источник


Ответы (2)


Несколько замечаний: Смешивать library(clpfd) и (is)/2 в основном не очень хорошая идея. Вы можете написать X #= Y + 1 вместо X is Y + 1 почти с той же эффективностью (в SWI), но с большей универсальностью.

Интересующее вас отношение связывает i-е элементы трех списков. То есть мы можем написать: maplist(r, Xs, Ys, Zs), где r/3 — это отношение, которое вас интересует. Итак, мы должны определить r(X,Y,Z).

А как насчет abs(X)+abs(Y)+abs(Z) #= 1?

С помощью library(lambda) вы можете поместить все это в одну строку. :

maplist(\X^Y^Z^(abs(X)+abs(Y)+abs(Z) #= 1), Xs, Ys, Zs).
person false    schedule 22.08.2011
comment
Элегантный и простой. Очень полезно, и спасибо, что посоветовали мне не использовать is/2. - person Martino; 23.08.2011
comment
Другой вопрос. Как суммировать в списке, включая индекс? Например, как я могу просуммировать по i выражение I*A(I)? - person Martino; 23.08.2011
comment
Не существует общепринятого способа сделать это компактно. Так что лучше всего было бы написать его рекурсивно. - person false; 23.08.2011

Вы можете сделать это с помощью простой рекурсии. Программа только проверяет ввод, ее нельзя использовать для генерации решений. Если вам это нужно, вы должны сказать, какие значения разрешены в фактах, например. добавив onlyOne(0,0,1). onlyOne(0,0,-1). и т. д.

onlyOne(0,0,_).
onlyOne(0,_,0).
onlyOne(_,0,0).
onlyOne([],[],[]).
onlyOne([H1|T1],[H2|T2],[H3|T3]) :- onlyOne(H1,H2,H3), onlyOne(T1,T2,T3).

Изменить: перечитывая вопрос, я думаю, вам требуется, чтобы ровно одна запись была ненулевой, а не не более одной. В этом случае вам нужны эти правила вместо фактов:

onlyOne(0,0,X) :- X \= 0.
onlyOne(0,X,0) :- X \= 0.
onlyOne(X,0,0) :- X \= 0.
person Joe Lehmann    schedule 22.08.2011