简体   繁体   English

Prolog得到字符串的头尾

[英]Prolog getting head and tail of string

I'm trying to wrap my brain around Prolog for the first time (SWI-Prolog) and I'm struggling with what I'm sure are the basics. 我正试图将我的大脑第一次包裹在Prolog(SWI-Prolog),我正在努力克服我确定的基础知识。 I'm trying to take a string such as "pie" and print out the military NATO spelling of it to look something like this: 我正试图拿一个像“馅饼”这样的字符串并打印出军事北约拼写它看起来像这样:

spellWord("Pie").
Papa
India
Echo

Currently I'm just trying to verify that I'm using the [H|T] syntax and Write function correctly. 目前我只是想验证我正在使用[H | T]语法和Write函数。 My function is: 我的功能是:

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

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

When making a call to spellWord("Pie") . 当打电话给spellWord("Pie") this currently just returns false. 这当前只返回false。

Regardless of the Prolog system you are using and unless you have to maintain existing code, stick to set_prolog_flag(double_quotes, chars) . 无论您使用的是Prolog系统,除非必须维护现有代码,否则请坚持使用set_prolog_flag(double_quotes, chars) This works in many systems like B, GNU, IF, IV, Minerva, SICStus, SWI, YAP. 这适用于许多系统,如B,GNU,IF,IV,Minerva,SICStus,SWI,YAP。 So it is a safe bet. 所以这是一个安全的赌注。 The other options mentioned by @Boris are hard to debug. @Boris提到的其他选项很难调试。 One is even specific to SWI only. 一个甚至仅针对SWI。

?- set_prolog_flag(double_quotes, chars).
true.

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

With library(double_quotes) these strings can be printed more compactly. 使用library(double_quotes)可以更紧凑地打印这些字符串。

In SWI, the best you can do is to put in your .swiplrc the lines: 在SWI中,您可以做的最好的事情是在.swiplrc以下行:

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

For your concrete example, it is a good idea to avoid producing side-effects immediately. 对于您的具体示例,最好立即避免产生副作用。 Instead consider defining a relation between a word and the spelling: 而是考虑定义单词和拼写之间的关系:

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".

And here is your original definition. 这是你原来的定义。 Most of the time, however, rather stick with the pure core of it. 然而,大部分时间都坚持使用它的纯粹核心。

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

Also note that SWI's built-in library(pio) only works for codes and leaves unnecessary choice-points open. 另请注意,SWI的内置library(pio)仅适用于代码,并且会打开不必要的选择点。 Instead, use this replacement which works for chars and codes depending on the Prolog flag. 相反,根据Prolog标志使用此替换符合charscodes

Historically, characters were first represented as atoms of length one. 历史上,字符首先表示为长度为1的原子。 That is, 1972 in Prolog 0. However, there, strings were represented in a left-associative manner which facilitated suffix matching. 也就是说,1972年在Prolog 0中。然而,在那里,字符串以左关联方式表示,这有利于后缀匹配。

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

Starting with Prolog I, 1973, double quotes meant a list of characters like today. 从1973年的Prolog I开始,双引号意味着像今天一样的字符列表。

In 1977, DECsystem 10 Prolog changed the meaning of double quotes to lists of characters codes and used codes in place of chars. 1977年,DECsystem 10 Prolog将双引号的含义更改为字符代码列表,并使用代码代替字符。 This made some I/O operations a little bit more efficient, but made debugging such programs much more difficult [76,105,107,101,32,116,104,105,115] - can you read it? 这使得一些I / O操作更有效率,但是调试这样的程序要困难得多[76,105,107,101,32,116,104,105,115] - 你能读懂它吗?

ISO Prolog supports both. ISO Prolog支持两者。 There is a flag double_quotes that indicates how double quotes are interpreted . 有一个标志double_quotes ,表示如何解释双引号 Also, character related built-ins are present for both: 此外,两个字符相关的内置函数都存在:

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

SWI-Prolog has several different representation of what you might call "strings". SWI-Prolog有几种不同的表示形式,你可以称之为“字符串”。

  • List of character codes (Unicode); 字符代码列表(Unicode);
  • List of chars (one-letter atoms); 字符列表(单字母原子);
  • Strings, which are "atomic" objects, and can be manipulated only with the built-in predicates for strings; 字符串,它们是“原子”对象,只能使用字符串的内置谓词进行操作;
  • And finally, of course, atoms. 最后,当然,原子。

You should read the documentation, but for now, you have at least two choices. 您应该阅读文档,但是现在,您至少有两个选择。

Choice 1 : Use a flag to make double-quoted strings code lists 选择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].

At this point, your approach should work, as you now have a list. 此时,您的方法应该有效,因为您现在有一个列表。

Choice 2 : Use the new code list syntax with back-ticks 选择2 :使用带有反向标记的新代码列表语法

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

And, of course, there are predicates that convert between atoms, code lists, char lists, and strings. 当然,有些谓词可以在原子,代码列表,字符列表和字符串之间进行转换。 So, to make a list of chars (one-character atoms), you have: 因此,要制作一个字符列表(一个字符的原子),你有:

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

As for your predicate definition, consider using unification in the head. 至于你的谓词定义,考虑在头部使用统一。 Also, don't mix side effects (printing) with what the predicate does. 另外,不要将副作用(打印)与谓词的作用混合在一起。 Let the top level (the Prolog interpreter) do the printing for you. 让顶级(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).

And with this: 有了这个:

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

I used chars (one-letter atoms) instead of character codes because those are easier to write. 我使用字符(单字母原子)而不是字符代码,因为它们更容易编写。


And finally, you can use the following flag, and set_prolog_flag/2 at run time to change how Prolog treats a string enclosed in double quotes. 最后,您可以在运行时使用以下标志和set_prolog_flag/2来更改Prolog处理用双引号括起来的字符串的方式。

For example: 例如:

$ 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.

The problems with your code are: 您的代码存在以下问题:

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

When you give this predicate a long string, it will invoke itself with the tail of that string. 当你给这个谓词一个长字符串时,它会用该字符串的尾部调用它自己。 But when String is empty, it cannot be split into [H|T] , therefore the predicate fails, returning false . 但是当String为空时,它不能被分割为[H|T] ,因此谓词失败,返回false

To fix this, you have to define additionally: 要解决此问题,您还必须另外定义:

spellWord([]).

This is the short form of: 这是简短的形式:

spellWord(String) :- String = [].

Your other predicate also has a problem: 你的另一个谓词也有问题:

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

You have two variables here, String and H . 这里有两个变量, StringH These variables are in no way related. 这些变量绝不相关。 So no matter what you pass as a parameter, it will not influence the H that you use for comparison. 因此,无论您作为参数传递什么,它都不会影响您用于比较的H And since the == operator only does a comparison, without unification, writeChar fails at this point, returning false . 由于==运算符只进行比较,没有统一, writeChar失败,返回false This is the reason why there is no output at all. 这就是为什么根本没有输出的原因。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM