Аргументы недостаточно инстанцированы SWI-Prolog

Я пытаюсь написать сценарий Prolog, который может создать список строк, который после простой процедуры приведет к заданной строке. Мои знания Пролога очень ограничены, и я не уверен, что он вообще может это сделать, поэтому, пожалуйста, скажите мне, если это невозможно.

Я получил это до сих пор

replace_word(Old, New, Orig, Replaced) :-
    atomic_list_concat(Split, Old, Orig),
    atomic_list_concat(Split, New, Replaced).

Он может выполнить эту операцию

10 ?- replace_word('a','e','glava',X).
X = gleve.

Но он не может отказаться от него.

11 ?- replace_word('a','e',X,'gleve').
ERROR: atomic_list_concat/3: Arguments are not sufficiently instantiated

Я могу представить себе причину проблемы, но есть ли способ ее обойти?


person 123 456    schedule 27.07.2012    source источник


Ответы (2)


Конечно, должны быть другие варианты реализации этого, и я не эксперт по Prolog, но кажется, что atomic_list_concat/3 не будет принимать две переменные в качестве аргументов (учитывая, что делает этот предикат, это было бы сложно, не так ли?), Поэтому вы можете обойти проблему с присвоением переменной, изменив порядок предложений, чтобы «исправить» переменные, которые вы знаете раньше. Например:

replace_word(Old, New, Orig, Replaced) :-
    (var(Orig), !, atomic_list_concat(Split, New, Replaced),
     atomic_list_concat(Split, Old, Orig)) ;
    (atomic_list_concat(Split, Old, Orig),
     atomic_list_concat(Split, New, Replaced)).

Обратите внимание, что в разрезе нет необходимости, но теперь вы можете делать то, о чем просите:

?- replace_word('a','e',X,'gleve').
X = glava.

?- replace_word('a','e','glava',Y).
Y = gleve.
person Diego Sevilla    schedule 27.07.2012
comment
Проблема в том, что мне требуется каждый X, который может приводить к 'gleve', включая 'gleve', 'glave', 'gleva' и 'glava'. - person 123 456; 28.07.2012
comment
@Diego Sevilla: сокращение необходимо, если вы не используете nonvar(Orig) в качестве альтернативы. Но, вероятно, лучше использовать if-then-else. - person false; 28.07.2012

replace_word / 4 был написан таким образом для повышения эффективности благодаря первоклассной обработке атомов SWI-Prolog. Я не вижу лучшего способа «перевернуть» его семантику, чем использование вспомогательного предиката:

replace_word(Old, New, Orig, Replaced) :-
    (   var(Orig)
    ->  atomic_list_concat(L, New, Replaced),
        insert_alt(L, [Old, New], L1),
        atomic_list_concat(L1, Orig)
    ;   atomic_list_concat(L, Old, Orig),
        atomic_list_concat(L, New, Replaced)
    ).
insert_alt([A,B|R], Ks, [A,K|T]) :-
    member(K, Ks),
    insert_alt([B|R], Ks, T).
insert_alt([A], _Ks, [A]).

insert_alt / 3 немного более общий, чем требуется, вместо списка (Ks) можно использовать пару Old-New ....

контрольная работа:

?- replace_word('a','e',X,'gleve').
X = glava ;
X = glave ;
X = gleva ;
X = gleve ;
false.
person CapelliC    schedule 31.07.2012