2016-04-13 38 views
7

Sto cercando di avvolgere il mio cervello intorno a Prolog per la prima volta (SWI-Prolog) e sto lottando con quello che sono sicuro sono le basi. Sto cercando di prendere una stringa come "torta" e stampare l'ortografia militare della NATO di farlo sembrare qualcosa di simile:Prolog ottenere la testa e la coda di stringa

spellWord("Pie"). 
Papa 
India 
Echo 

Attualmente mi sto solo cercando di verificare che sto usando il [ H | T] sintassi e scrittura funzionano correttamente. La mia funzione è:

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

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

Quando si effettua una chiamata a spellWord("Pie"). questo al momento restituisce solo false.

risposta

6

SWI-Prolog ha diverse rappresentazioni di ciò che potreste chiamare "stringhe".

  • Elenco di codici di caratteri (Unicode);
  • Elenco di caratteri (atomi di una lettera);
  • Stringhe, che sono oggetti "atomici" e possono essere manipolate solo con i predicati incorporati per le stringhe;
  • E infine, naturalmente, gli atomi.

Si consiglia di leggere la documentazione, ma per ora sono disponibili almeno due opzioni.

Scelta 1: Utilizzare una bandiera per rendere il codice stringhe tra doppi apici elenca

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

A questo punto, il vostro approccio dovrebbe funzionare, come adesso avete una lista.

Scelta 2: Utilizzare la nuova sintassi lista dei codici di back-zecche

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

E, naturalmente, ci sono predicati che convertono tra gli atomi, elenchi di codici, elenchi char e stringhe . Così, per fare un elenco di caratteri (atomi di un carattere), si ha:

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

Per quanto riguarda la sua definizione predicato, è possibile utilizzare l'unificazione nel capo. Inoltre, non mescolare gli effetti collaterali (stampa) con ciò che fa il predicato. Lascia che il livello più alto (l'interprete di Prolog) faccia la stampa per te.

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

E con questo:

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

ho usato caratteri (atomi di una sola lettera) anziché i codici di carattere perché quelli sono più facili da scrivere.


E, infine, è possibile utilizzare il seguente bandiera, e set_prolog_flag/2 in fase di esecuzione per cambiare il modo Prolog considera una stringa racchiusa tra doppi apici.

Ad esempio:

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

Come farei questo lavoro per accettare l'input tra virgolette singole, ad esempio "pie" – donsavage

+0

@donsavage Basta utilizzare prima il predicato di conversione appropriato. Li ho elencati nella risposta sopra. –

+1

C'è anche l'opzione 'set_prolog_flag (double_quotes, chars)' – false

7

Indipendentemente dal sistema Prolog in uso e se non si dispone di mantenere il codice esistente, attenersi a set_prolog_flag(double_quotes, chars). Funziona in many systems come B, GNU, IF, IV, Minerva, SICStus, SWI, YAP. Quindi è una scommessa sicura . Le altre opzioni menzionate da @ Boris sono difficili da eseguire. Uno è addirittura specifico solo per SWI .

?- set_prolog_flag(double_quotes, chars). 
true. 

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

Con library(double_quotes) queste stringhe possono essere stampati in modo più compatto.

Nel SWI, il meglio che puoi fare è di mettere nelle vostre .swiplrc le righe:

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

Per esempio concreto, è una buona idea per evitare di produrre immediatamente effetti collaterali. Invece considerare la definizione di una relazione tra una parola e l'ortografia:

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

E qui è la sua definizione originale. La maggior parte delle volte, tuttavia, si attaccano al nucleo puro di esso.

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

Si noti inoltre che SWI di built-in library(pio) funziona solo per i codici e lascia inutili scelta punti aperti. Utilizzare invece this replacement che funziona per chars e codes in base alla bandiera Prolog.

Storicamente, i caratteri erano rappresentati per la prima volta come atomi di lunghezza . Cioè, 1972 in Prolog 0. Tuttavia, lì, le stringhe erano rappresentate in un modo associativo sinistro che facilitava la corrispondenza del suffisso.

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

Partendo Prolog I, 1973, le doppie virgolette significava un elenco di caratteri come oggi.

Nel 1977, DECsystem 10 Prolog ha cambiato il significato delle virgolette in elenchi di codici di caratteri e codici usati al posto di caratteri. Ciò ha reso alcune operazioni I/O un po 'più efficienti, ma reso più difficile il debug di tali programmi [76,105,107,101,32,116,104,105,115] - puoi leggerlo?

ISO Prolog supporta entrambi. C'è una bandiera double_quotes che indica how double quotes are interpreted.Inoltre, carattere relativi built-in sono presenti per entrambi:

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 
1

I problemi con il codice sono:

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

Quando si dà questo predicato una lunga serie, si invocherà con la coda di quella stringa. Ma quando String è vuoto, non può essere diviso in [H|T], pertanto il predicato non riesce, restituendo false.

Per risolvere questo problema, è necessario definire ulteriormente:

spellWord([]). 

Questa è la forma abbreviata di:

spellWord(String) :- String = []. 

tua altra predicato ha anche un problema:

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

Hai due variabili qui, String e H. Queste variabili non sono in alcun modo correlate. Quindi, indipendentemente da ciò che passi come parametro, non influenza il H che usi per il confronto. E poiché l'operatore == esegue solo un confronto, senza unificazione, writeChar non riesce a questo punto, restituendo false. Questo è il motivo per cui non vi è alcun output.

+1

C'è ancora il problema con ciò che si chiama una stringa e se si tratta di una lista. Se si installa l'ultimo SWI-Prolog e si digita una stringa tra virgolette, come in "" pippo "', questo è _most decisamente_non una lista, ma un oggetto atomico. –

+1

PS. Anche se il predicato 'spellWord/1' fallirà, dovrebbe stampare ogni elemento della lista. Quindi, in un certo modo, fa ciò che era destinato a fare. –