Использование сопоставления с образцом в Прологе для поиска подмножеств

Я новичок в прологе, и мне было интересно, если кто-нибудь может помочь мне с этой проблемой. Проблема: учитывая целые числа 1,2,3,4 и предикаты mult / 2, div / 2, div / 2, минус / 2 и минус / 2 и eval / 2, мне нужно написать предикатное решение /1 что при вызове так:

?- solutions(L).

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

X, Y, exp/2

Но мой код не работает. У меня есть две версии. Первый замораживает SWI-Prolog, не возвращая никакого ответа после того, как я ввел точку, и не позволяя мне оценить что-либо еще потом:

eval(1,1.0).
eval(2,2.0).
eval(3,3.0).
eval(4,4.0).

eval(mult(X,Y),Z) :-
    eval(X,A),
    eval(Y,B),
    Z is A*B.

eval(div(X,Y),Z) :-
    eval(X,A),
    eval(Y,B),
    Z is A/B.

eval(minus(X,Y),Z) :-
    eval(X,A),
    eval(Y,B),
    Z is A-B.

solutions(L) :-
    setof(X,eval(X,6),L),
    print(L).

Вторая версия просто возвращает ложь, когда я печатаю ?- solutions(L).:

solutions(L) :-
    setof([exp,X,Y],eval(exp(X,Y),6),L),
    print(L).

Большое спасибо, что нашли время, чтобы помочь!

2 ответа

Решение

Может быть, вы ищете что-то вроде

solutions(L) :-
    Ns = [1,2,3,4],
    Ex = [*,/,-],
    findall((X,Y,E),
       (member(X,Ns),member(Y,Ns),member(E,Ex),F=..[E,X,Y],6=:=F),
       L).

что дает

?- solutions(L).
L = [(2, 3,  (*)),  (3, 2,  (*))].

Выражения обычно являются рекурсивными, то есть аргументы могут быть выражениями вместо простых чисел. Но тогда, на мой взгляд, ваша проблема недостаточно конкретизирована, так как нам нужны критерии, чтобы остановить бесконечный поток решений, возникающих, например, в результате повторного применения операций, которые не меняют значение. Как умножить или разделить на 1.

Проблема в том, что ваш код работает в бесконечной рекурсии с предикатом eval/2.

Вы можете попробовать это решение:

num(1).
num(2).
num(3).
num(4).

eval(mult(A,B),Z) :-
    num(A),
    num(B),
    Z is A*B.

eval(div(A,B),Z) :-
    num(A),
    num(B),
    Z is A/B.

eval(minus(A,B),Z) :-
    num(A),
    num(B),
    Z is A-B.

test(L) :-
    setof(X,eval(X,6),L),
    print(L). 

Который дает:

?- test(L).
[mult(2,3),mult(3,2)]
L = [mult(2, 3), mult(3, 2)].
Другие вопросы по тегам