Пролог получает голову и хвост струны

Я пытаюсь обернуть свой мозг вокруг Пролога в первый раз (SWI-Пролог), и я борюсь с тем, что, я уверен, является основами. Я пытаюсь взять строку, такую ​​как "пирог", и распечатать военную натовскую орфографию, чтобы она выглядела примерно так:

spellWord("Pie").
Papa
India
Echo

В настоящее время я просто пытаюсь проверить, правильно ли я использую синтаксис [H|T] и функцию Write. Моя функция:

spellWord(String) :- String = [H|T], writeChar(H), spellWord(T).

writeChar(String) :- H == "P", print4("Papa").

При звонке в spellWord("Pie"), это в настоящее время просто возвращает ложь.

3 ответа

Решение

SWI-Prolog имеет несколько разных представлений о том, что вы могли бы назвать "строками".

  • Список кодов символов (Unicode);
  • Список символов (однобуквенные атомы);
  • Строки, которые являются "атомарными" объектами и могут управляться только с помощью встроенных предикатов для строк;
  • И, наконец, конечно, атомы.

Вам следует прочитать документацию, но на данный момент у вас есть как минимум два варианта.

Вариант 1. Использование флага для составления списков кодов строк в двойных кавычках

$ swipl --traditional
Welcome to SWI-Prolog (Multi-threaded, 64 bits, Version 7.3.19-57-g9d8aa27)
Copyright (c) 1990-2015 University of Amsterdam, VU Amsterdam
SWI-Prolog comes with ABSOLUTELY NO WARRANTY. This is free software,
and you are welcome to redistribute it under certain conditions.
Please visit http://www.swi-prolog.org for details.

For help, use ?- help(Topic). or ?- apropos(Word).

?- X = "abc".
X = [97, 98, 99].

На этом этапе ваш подход должен работать, так как у вас теперь есть список.

Выбор 2: использовать новый синтаксис списка кодов с обратными галочками

?- X = `abc`.
X = [97, 98, 99].

И, конечно же, существуют предикаты, которые преобразуют атомы, списки кодов, списки символов и строки. Итак, чтобы составить список символов (односимвольных атомов), у вас есть:

  • atom_chars/2
  • char_code/2
  • string_chars/2

Что касается определения предиката, подумайте об объединении в голове. Кроме того, не смешивайте побочные эффекты (печать) с тем, что делает предикат. Пусть верхний уровень (переводчик Prolog) сделает печать за вас.

nato(p, 'Papa').
nato(i, 'India').
nato(e, 'Echo').
% and so on

word_nato([], []).
word_nato([C|Cs], [N|Ns]) :-
    char_code(Char, C),
    char_type(U, to_lower(Char)),
    nato(U, N),
    word_nato(Cs, Ns).

И с этим:

?- word_nato(`Pie`, Nato).
Nato = ['Papa', 'India', 'Echo'].

Я использовал символы (однобуквенные атомы) вместо кодов символов, потому что их легче писать.


И, наконец, вы можете использовать следующий флаг, и set_prolog_flag/2 во время выполнения, чтобы изменить способ обработки Прологом строки, заключенной в двойные кавычки.

Например:

$ swipl
Welcome to SWI-Prolog (Multi-threaded, 64 bits, Version 7.3.19-40-g2bcbced)
Copyright (c) 1990-2015 University of Amsterdam, VU Amsterdam
SWI-Prolog comes with ABSOLUTELY NO WARRANTY. This is free software,
and you are welcome to redistribute it under certain conditions.
Please visit http://www.swi-prolog.org for details.

For help, use ?- help(Topic). or ?- apropos(Word).

?- current_prolog_flag(double_quotes, DQs).
DQs = string.

?- string("foo").
true.

?- set_prolog_flag(double_quotes, codes).
true.

?- X = "foo".
X = [102, 111, 111].

?- set_prolog_flag(double_quotes, chars).
true.

?- X = "foo".
X = [f, o, o].

?- set_prolog_flag(double_quotes, atom).
true.

?- X = "foo".
X = foo.

Независимо от системы Prolog, которую вы используете, и если вам не нужно поддерживать существующий код, придерживайтесь set_prolog_flag(double_quotes, chars), Это работает во многих системах, таких как B, GNU, IF, IV, Minerva, SICStus, SWI, YAP. Так что это безопасная ставка. Другие параметры, упомянутые @Boris, трудно отлаживать. Один относится только к SWI.

?- set_prolog_flag(double_quotes, chars).
true.

?- L = "abc".
L = [a, b, c].

С library(double_quotes) эти строки могут быть напечатаны более компактно.

В SWI лучшее, что вы можете сделать, это вставить свой .swiplrc линии:

:- set_prolog_flag(back_quotes, string).
:- set_prolog_flag(double_quotes, chars).
:- use_module(library(double_quotes)).

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

word_spelling(Ws, Ys) :-
   phrase(natospelling(Ws), Ys).

natospelling([]).
natospelling([C|Cs]) -->
   {char_lower(C, L)},
   nato(L),
   "\n",
   natospelling(Cs).

nato(p) --> "Papa".
nato(i) --> "India".
nato(e) --> "Echo".

char_lower(C, L) :-
   char_type(L, to_lower(C)).

?- word_spelling("Pie",Xs).
Xs = "Papa\nIndia\nEcho\n".

?- word_spelling("Pie",Xs), format("~s",[Xs]).
Papa
India
Echo
Xs = "Papa\nIndia\nEcho\n".

А вот и ваше оригинальное определение. Однако большую часть времени, скорее, придерживайтесь чистого ядра.

spellWord(Ws) :-
   word_spelling(Ws, Xs),
   format("~s", [Xs]).

Также обратите внимание, что встроенный в SWI library(pio) работает только для кодов и оставляет ненужные точки выбора открытыми. Вместо этого используйте эту замену, которая работает для chars а также codes в зависимости от флага Пролог.

Исторически персонажи были впервые представлены как атомы длиной один. То есть 1972 год в Прологе 0. Однако там строки были представлены левоассоциативным образом, что облегчало сопоставление суффиксов.

plur(nil-c-i-e-l, nil-c-i-e-u-x).

Начиная с Пролога I, 1973, двойные кавычки означали список символов, как сегодня.

В 1977 году DECsystem 10 Prolog изменила значение двойных кавычек на списки кодов символов и использовала коды вместо символов. Это сделало некоторые операции ввода-вывода немного более эффективными, но значительно усложнило отладку таких программ [76,105,107,101,32,116,104,105,115] - вы можете прочитать это?

ISO Prolog поддерживает оба. Есть флаг double_quotes это указывает, как двойные кавычки интерпретируются. Кроме того, связанные с персонажем встроенные модули присутствуют для:

char_code/2

atom_chars/2, number_chars/2, get_char/1/2, peek_char/1/2, put_char/1/2

atom_codes/2, number_codes/2, get_code/1/2, peek_code/1/2, put_code/1/2

Проблемы с вашим кодом:

spellWord(String) :- String = [H|T], writeChar(H), spellWord(T).

Когда вы дадите этому предикату длинную строку, он вызовет себя с хвостом этой строки. Но когда String пусто, его нельзя разбить на [H|T]поэтому предикат не работает, возвращая false,

Чтобы это исправить, вы должны определить дополнительно:

spellWord([]).

Это краткая форма:

spellWord(String) :- String = [].

Ваш другой предикат также имеет проблему:

writeChar(String) :- H == "P", print4("Papa").

У вас есть две переменные здесь, String а также H, Эти переменные никоим образом не связаны. Поэтому независимо от того, что вы передаете в качестве параметра, это не повлияет на H что вы используете для сравнения. И так как == оператор только делает сравнение, без унификации, writeChar терпит неудачу в этой точке, возвращая false, Это причина, по которой вообще нет выхода.

Другие вопросы по тегам