Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/list/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
String Prolog获取字符串的头和尾_String_List_Prolog_Dcg - Fatal编程技术网

String Prolog获取字符串的头和尾

String Prolog获取字符串的头和尾,string,list,prolog,dcg,String,List,Prolog,Dcg,我第一次试着用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",

我第一次试着用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").

调用
拼写单词(“Pie”)
时。这目前只返回false。

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\u chars/2
  • char\u code/2
  • string\u 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\u prolog\u标志/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\u prolog\u标志(双引号,字符)
。这在中国很管用 比如B,GNU,IF,IV,Minerva,SICStus,SWI,YAP。所以这是一个保险箱 打赌@Boris提到的其他选项很难调试。一个甚至是针对SWI的 只是

与 这些字符串可以打印得更紧凑

在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的内置
库(pio)
仅适用于 编码并留下不必要的选择点。相反,使用 它适用于
字符
代码
,具体取决于Prolog标志

历史上,字符最初是以长度的原子来表示的 一个。也就是说,在序言0中是1972年。然而,在那里,字符串是不存在的 以左联想的方式表示,这有助于后缀匹配

plur(nil-c-i-e-l, nil-c-i-e-u-x).
从1973年的Prolog I开始,双引号表示字符列表 就像今天一样

1977年,DECsystem 10 Prolog改变了双引号的含义 到字符代码列表和用代码代替字符。这导致了一些I/O操作 效率提高了一点,但调试这些程序的效率却提高了很多 更难[76105107101,32116104105115]-你能读懂吗

ISO Prolog支持这两种方法。有一个标志
双引号
表示。也,
以下两种类型都有与字符相关的内置功能:

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
。这就是根本没有输出的原因。

我如何才能接受单引号中的输入,例如'pie'@donsavage,请先使用适当的转换谓词。我在上面的答案中列出了它们。还有选项
set\u prolog\u flag(双引号,字符)
@false是,但您必须在程序中明确设置它,而不是使用命令行标志?我想了想,但我认为这是离题的。。。。为了完整起见,我应该添加它。您所称的字符串以及它是否是列表仍然存在问题。如果您只是安装最新的SWI Prolog,并在双引号之间键入一个字符串,如
“foo”
,那么这肯定不是一个列表,而是一个原子对象.PS。即使谓词
spellWord/1
将失败,它也应该打印出列表中的每个元素。因此,在某种程度上,它做到了它的本意。
writeChar(String) :- H == "P", print4("Papa").