Prolog获取字符串的头部和尾部
Prolog getting head and tail of string
我第一次尝试全神贯注于 Prolog (SWI-Prolog),我正在为我确定的基础知识而苦苦挣扎。我正在尝试使用 "pie" 之类的字符串并打印出它的军事北约拼写,看起来像这样:
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")
时。这目前只是 returns false。
SWI-Prolog 有几种不同的表示形式,您可以称之为 "strings"。
- 字符代码列表(Unicode);
- 字符列表(单字母原子);
- 字符串,是 "atomic" 个对象,只能使用内置的字符串谓词进行操作;
- 最后当然是原子。
您应该阅读文档,但目前,您至少有两个选择。
选择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
来更改 Prolog 处理双引号括起来的字符串的方式。
例如:
$ 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、Scryer、SICStus、SWI、Tau、Trealla、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)
仅适用于
编码并留下不必要的选择点。相反,使用 this
替换
根据 Prolog 标志,它适用于 chars
和 codes
。
从历史上看,字符首先表示为长度的原子
一。也就是说,Prolog 0 中的 1972 年。然而,在那里,字符串是
以有助于后缀匹配的左关联方式表示。
plur(nil-c-i-e-l, nil-c-i-e-u-x).
从 1973 年的 Prolog I 开始,双引号表示字符列表
就像今天一样。
1977年DECsystem 10 Prolog改变了双引号的含义
到字符代码列表和使用的代码代替字符。这进行了一些 I/O 操作
效率更高一点,但使调试此类程序变得更加困难
更难 [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
。这就是为什么根本没有输出的原因。
我第一次尝试全神贯注于 Prolog (SWI-Prolog),我正在为我确定的基础知识而苦苦挣扎。我正在尝试使用 "pie" 之类的字符串并打印出它的军事北约拼写,看起来像这样:
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")
时。这目前只是 returns false。
SWI-Prolog 有几种不同的表示形式,您可以称之为 "strings"。
- 字符代码列表(Unicode);
- 字符列表(单字母原子);
- 字符串,是 "atomic" 个对象,只能使用内置的字符串谓词进行操作;
- 最后当然是原子。
您应该阅读文档,但目前,您至少有两个选择。
选择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
来更改 Prolog 处理双引号括起来的字符串的方式。
例如:
$ 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、Scryer、SICStus、SWI、Tau、Trealla、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)
仅适用于
编码并留下不必要的选择点。相反,使用 this
替换
根据 Prolog 标志,它适用于 chars
和 codes
。
从历史上看,字符首先表示为长度的原子 一。也就是说,Prolog 0 中的 1972 年。然而,在那里,字符串是 以有助于后缀匹配的左关联方式表示。
plur(nil-c-i-e-l, nil-c-i-e-u-x).
从 1973 年的 Prolog I 开始,双引号表示字符列表 就像今天一样。
1977年DECsystem 10 Prolog改变了双引号的含义 到字符代码列表和使用的代码代替字符。这进行了一些 I/O 操作 效率更高一点,但使调试此类程序变得更加困难 更难 [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
。这就是为什么根本没有输出的原因。