2015-11-07 4 views
1

У меня возникли проблемы с выяснением простой проблемы Prolog. Мне нужно выполнить какую-то манипуляцию (определенную мной) на элементах списка атомов. Тем не менее, я должен выполнять такую ​​манипуляцию, если элемент, о котором идет речь о списке, возвращает true для заданного предиката P (x).Функция смены списка

Так в основном, если у меня есть правило:

mutate_if(isOdd, addOne, [1,2,3,4,5], L2). 

я должен получить следующий вывод:

L2 = [2,2,4,4,6] 

Я пришел с этим кодом до сих пор

mutate_if(P, OP, L1, L2):- 
    findall(Y, ((member(X,L1), 
    Oper=.. [P,X], 
    call(Oper)) -> (Mutate=.. [OP, X, Y], call(Mutate)); X=Y), 
    L2). 

В моей голове это должно работать хорошо, однако, когда я запускаю это на Prolog-SWI, я получаю следующее:

?- mutate_if(isOdd, addOne, [1,2,3,4,5], L2).< 
L2=[2]. 

, где isOdd и addOne являются простые правила, которые проверяют, чтобы увидеть, если входная переменная является нечетным, и добавьте к входной переменной, соответственно.

Не могу понять, почему Prolog находит только один элемент списка, когда предикат findall должен технически находить всех членов первого списка.

Является ли это ошибкой в ​​моей собственной логике?

ответ

2

Несколько предложений ...

Вам не нужно =../2 для этого. call(P, X) вызовет функтор P с аргументом X и call(OP, X, Y) вызовет функтор OP с аргументами X и Y.

Здесь вы можете использовать findall, если вы правильно установили свое состояние. Он будет собирать значения, которые приводят к тому, что данное выражение будет успешным (с получением true). Так как вы хотите карты каждый элемента списка в результат, я хотел бы использовать maplist/3 с предикатом, как, mutate_one_if(P, OP, X, Y), который мутирует один X к Y или оставляет его в покое (X = Y) в зависимости от состояния (как вы требуете) ,

mutate_one_if(P, OP, X, Y) :- 
    ( call(P, X) 
    -> call(OP, X, Y) 
    ; X = Y 
    ). 

mutate_if(P, OP, L1, L2) :- 
    maplist(mutate_one_if(P, OP), L1, L2). 

maplist/3 будет называть mutate_one_if(P, OP) для каждого соответствующего элемента из L1 и L2. Как вы можете видеть, call очень гибкий, поскольку, если вы хотите позвонить mutate_one_if(P, OP, X, Y), вы можете назвать его как, call(mutate_one_if(P, OP), X, Y) или как call(mutate_one_if(P, OP, X, Y)). Prolog's call соберет аргументы соответствующим образом.

Таким образом, используя эти:

isOdd(X) :- X /\ 1 =:= 1. 
addOne(X, Y) := Y is X + 1. 

Урожайность:

| ?- mutate_if(isOdd, addOne, [1,2,3,4,5], L). 

L = [2,2,4,4,6] 

yes 
2

Я думаю, что вы не правильно обзорное 'тогда/Then/Else' операнды. С этим определением

mutate_if(P, OP, L1, L2):- 
    findall(Y, (
    member(X,L1), 
    Oper=.. [P,X], 
    (call(Oper) -> Mutate=.. [OP, X, Y], call(Mutate); X=Y) 
), L2). 

я получаю

?- mutate_if(isOdd, addOne, [1,2,3,4,5], L). 
L = [2, 2, 4, 4, 6]. 

(приписка к сведению, что @lurker предложения очень ценны)

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