После приведения формулы вида ПНФ к виду ССФ вы получаете формулу, в безквантовой матрице которой дизъюнкт содержит оба контранрных атома:. Как тогда проводить его унификацию, если в случае замены x на f(x) весь дизъюнкт обратится в единицу? |
Строки
Пример. Разработаем предикат, который будет удалять часть строки. Предикат будет иметь четыре параметра. Первые три входные: первый — исходная строка, второй — позиция, начиная с которой нужно удалять символы, третий — количество удаляемых символов. Четвертым — выходным — параметром будет результат удаления из строки, указанной в первом параметре, символов, в количестве, указанном в третьем параметре, начиная с позиции, указанной во втором параметре.
Запишем решение этой задачи. Начнем с того, что при помощи стандартного предиката frontstr разобьем исходную строку на две подстроки. Во вторую попадут все символы, начиная с той позиции, с которой нужно удалять символы. В первую — начало исходной строки. Вторую подстроку еще раз разделим на две подстроки. В первую подстроку поместим те символы, которые нужно удалить. В этом месте можно будет воспользоваться анонимной переменной. Во вторую подстроку попадут оставшиеся символы остатка исходной строки. Чтобы получить ответ, нам остается только соединить первую подстроку исходной строки с последней подстрокой второй подстроки. Мы получим строку, состоящую в точности из тех символов, которые и должны были остаться в итоговой строке.
Давайте запишем эти немного путаные размышления в виде предложения на Прологе.
str_delete(S,I,C,SO) :– I1=I–1, /* I1 — количество символов, которые должны остаться в начале строки S */ frontstr(I1,S,S1,S2), /* S1 — первые I1 символов строки S, S2 — символы строки S, с I —го до последнего */ frontstr(C,S2,_,S3), /* S3 — последние символы строки S2 ( или, что тоже самое, последние символы строки S */ concat(S1,S3,SO). /* SO — строка, полученная соединением строк S1 и S3 */
Пример. Не помешает иметь в нашем хозяйстве предикат, который будет копировать часть строки. Предикат будет иметь четыре параметра. Первые три входные: первый — исходная строка, второй — позиция, начиная с которой нужно копировать символы, третий — количество копируемых символов. Четвертым — выходным — параметром будет результат копирования символов из строки, указанной в первом параметре, в количестве, указанном в третьем параметре, начиная с позиции, указанной во втором параметре.
Для решения этой задачи опять воспользуемся предикатом frontstr. Сначала получим хвост нашей строки, начиная с той позиции, c которой нужно копировать символы. Если после этого взять столько первых символов новой строки, сколько их нужно копировать, получим в точности ту подстроку исходной строки, которую требуется получить.
Зафиксируем наши рассуждения.
str_copy(S,I,C,SO) :– I1=I–1, /* I1 — это количество символов, расположенных в начале строки S, которые не нужно копировать */ frontstr(I1,S,_,S1), /* S1 — строка, состоящая из всех символов строки S, с I-го и до последнего */ frontstr(C,S1,SO,_). /* SO — первые C символов строки S1 */
Пример. Мы реализовали почти все операции, которые есть в большинстве стандартных алгоритмических языков типа Паскаля. Недостает, наверное, только предиката, который позволит нам вставить одну строку внутрь другой строки. Предикат будет иметь четыре параметра. Первые три входные: первый — вставляемая строка ; второй — строка, в которую нужно вставить первый аргумент; третий — позиция, начиная с которой нужно вставить первый параметр во второй. Четвертым — выходным — параметром будет результат вставки строки, указанной в первом параметре, в строку, указанную во втором параметре, начиная с позиции, указанной в третьем параметре.
Для реализации этого предиката разделим, используя предикат frontstr, исходную строку на две подстроки. Во вторую поместим все символы, начиная с позиции, в которую должна быть вставлена вторая строка, в первую — оставшееся начало исходной строки. После этого припишем, используя конкатенацию, к полученной строке ту строку, которую нужно было вставить. Для получения окончательного результата нам остается только дописать вторую подстроку исходной строки.
Запишем:
str_insert(S,S1,I,SO) :– I1=I–1, /* I1 — это количество символов, расположенных в начале строки S, после которых нужно вставить новые символы */ frontstr(I1,S1,S1_1,S1_2), /* S1_1 — первые I1 символов строки S1, S1_2 — остаток строки S1, с I —го и до последнего */ concat(S1_1,S,S2), /* S2 — строка, полученная объединением строк S1_1 и S */ concat(S2,S1_2,SO). /* SO — строка, полученная слиянием строк S2 и S1_2 */
Пример. Создадим, для разнообразия, предикат, который будет подсчитывать количество имеющихся в строке цифр. Предикат будет иметь всего два аргумента. Входным аргументом будет строка, количество цифр в которой нужно подсчитать, выходным аргументом будет количество цифр в первом аргументе.
Для того чтобы реализовать этот предикат, нам придется разработать вспомогательный предикат, который будет означивать второй аргумент единицей (если его первый аргумент является цифрой) и нулем (в противном случае). Основной предикат будет использовать рекурсию по длине строки. Базисом будет очевидный факт, говорящий, что в пустой строке цифр нет. Непустую строку с помощью предиката frontchar разделим на первый символ и хвост. Подсчитаем количество цифр в хвосте, после чего к полученному числу добавим единицу, если первый символ — цифра, и ноль, если первый символ — не цифра.
Запишем оба предиката, вспомогательный и основной:
dig(C,1):– ‘0’<=C,C<=’9’,!. /* C — цифра*/ dig(_,0). count_digit("",0):–!. /* В пустой строке цифр нет */ count_digit(S,N):– frontchar(S,C,S2), /* C — первый символ строки S, S2 — хвост строки S */ dig(C,M), /* M равен единице, если C — цифра, и нулю — иначе */ count_digit(S2,N2), /* N2 — количество цифр в строке S2*/ N=N2+M. /* Количество цифр во всей строке больше на единицу, чем количество цифр в хвосте, если первый символ строки — цифра, и равно количеству цифр в хвосте — иначе */