簡體   English   中英

Prolog得到字符串的頭尾

[英]Prolog getting head and tail of string

我正試圖將我的大腦第一次包裹在Prolog(SWI-Prolog),我正在努力克服我確定的基礎知識。 我正試圖拿一個像“餡餅”這樣的字符串並打印出軍事北約拼寫它看起來像這樣:

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") 這當前只返回false。

無論您使用的是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)僅適用於代碼,並且會打開不必要的選擇點。 相反,根據Prolog標志使用此替換符合charscodes

歷史上,字符首先表示為長度為1的原子。 也就是說,1972年在Prolog 0中。然而,在那里,字符串以左關聯方式表示,這有利於后綴匹配。

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

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來更改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.

您的代碼存在以下問題:

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

當你給這個謂詞一個長字符串時,它會用該字符串的尾部調用它自己。 但是當String為空時,它不能被分割為[H|T] ,因此謂詞失敗,返回false

要解決此問題,您還必須另外定義:

spellWord([]).

這是簡短的形式:

spellWord(String) :- String = [].

你的另一個謂詞也有問題:

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

這里有兩個變量, StringH 這些變量絕不相關。 因此,無論您作為參數傳遞什么,它都不會影響您用於比較的H 由於==運算符只進行比較,沒有統一, writeChar失敗,返回false 這就是為什么根本沒有輸出的原因。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM