2016-04-13 28 views
7

Próbuję zawinąć mój mózg wokół Prologu po raz pierwszy (SWI-Prolog) i walczę z tym, co na pewno są podstawami. Próbuję wziąć ciąg takie jak „tortu” i wydrukować pisowni wojskowej NATO to wyglądać mniej więcej tak:Prolog dostaje głowę i ogon sznurka

spellWord("Pie"). 
Papa 
India 
Echo 

Obecnie jestem po prostu staramy się zweryfikować, Używam [ H | T] składnia i funkcja zapisu poprawnie. Moja funkcja to:

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

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

Podczas nawiązywania połączenia z numerem spellWord("Pie"). obecnie właśnie zwraca false.

Odpowiedz

6

SWI-Prolog ma kilka różnych reprezentacji tego, co można nazwać "łańcuchami".

  • Lista kodów znaków (Unicode);
  • Lista znaków (jednoliterowe atomy);
  • Łańcuchy, które są obiektami "atomowymi" i można nimi manipulować tylko za pomocą wbudowanych predykatów dla ciągów;
  • I wreszcie, oczywiście, atomy.

Powinieneś przeczytać dokumentację, ale na razie masz co najmniej dwie możliwości.

Wybór 1: Użyj flagę aby kod podwójnych cudzysłowów wymienia

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

W tym momencie twoje podejście powinno działać, jak masz teraz listę.

Wybór 2: Używaj nowej listy kod składni z back-kleszcze

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

I, oczywiście, są predykaty, które przekształcają między atomami, listy kodów, listy char i smyczki . Tak więc, aby zrobić listę znaków (atomy jeden znak), masz:

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

Co do definicji predykatu, należy rozważyć użycie unifikacji w głowa. Nie mieszaj efektów ubocznych (drukowania) z tym, co robi predykat. Pozwól, aby najwyższy poziom (interpreter Prolog) wydrukował dla Ciebie.

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

I z tym:

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

użyłem znaków (atomy jedna litera) zamiast kodów znaków, ponieważ są łatwiejsze do napisania.


I wreszcie, można użyć następującego flagę i set_prolog_flag/2 w czasie wykonywania, aby zmienić sposób Prolog traktuje ciąg ujęty w cudzysłów.

Na przykład:

$ 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

Jak mogę to zrobić, aby zaakceptować dane wejściowe w pojedynczym cudzysłowie, takie jak "ciasto" – donsavage

+0

@donsavage Wystarczy użyć odpowiedniego predykatu konwersji w pierwszej kolejności. Wymieniłem je w powyższej odpowiedzi. –

+1

Istnieje również opcja 'set_prolog_flag (double_quotes, chars)' – false

7

Niezależnie od systemu Prolog używasz i chyba trzeba utrzymania istniejącego kodu, trzymać się set_prolog_flag(double_quotes, chars). Działa to w postaci many systems , takich jak B, GNU, IF, IV, Minerva, SICStus, SWI, YAP. Więc jest to bezpieczny zakład . Inne opcje wymienione przez @Boris są trudne do debugowania. Jeden jest nawet specyficzny tylko dla SWI .

?- set_prolog_flag(double_quotes, chars). 
true. 

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

Z library(double_quotes) te łańcuchy mogą być drukowane bardziej zwarty.

W SWI, najlepiej można zrobić, to umieścić w swoim .swiplrc liniach:

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

Dla Państwa konkretny przykład, to jest dobry pomysł, aby uniknąć wytwarzania skutki uboczne natychmiast. Zamiast rozważać definiowania relacji między słowem i pisowni:

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

I tu jest oryginalna definicja. W większości przypadków jednak należy trzymać się jego czystego rdzenia.

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

Należy również pamiętać, że SWI wbudowanej library(pio) działa tylko dla kodów i pozostawia niepotrzebne dotyczącej wyboru punktów otwarte. Zamiast tego użyj this replacement , która działa dla chars i codes w zależności od flagi Prolog.

Historycznie znaki były najpierw reprezentowane jako atomy o długości . Oznacza to, że w 1972 w Prologu 0, łańcuchy były reprezentowane w sposób lewostronny, co ułatwiło dopasowanie sufiksu.

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

Począwszy Prolog I, 1973, cudzysłowy oznaczało listę znaków jak dzisiaj.

W 1977 roku, DECsystem 10 Prolog zmienił znaczenie podwójnych cytatów do list kodów znaków i używanych kodów w miejsce znaków. To sprawiło, że niektóre operacje we/wy były nieco bardziej wydajne, ale sprawiły, że debugowanie takich programów było o wiele trudniejsze [76,105,107,101,32,116,104,105,115] - czy możesz je przeczytać?

ISO Prolog obsługuje oba. Jest flaga double_quotes, którą oznacza how double quotes are interpreted.Również charakter związane Zabudowy są obecni zarówno:

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

Problemy z kodem są:

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

Kiedy dajesz tego predykatu długi ciąg, będzie powoływać się z ogonem tego ciągu. Ale gdy String jest pusty, nie można go podzielić na [H|T], dlatego predykat kończy się niepowodzeniem, zwracając false.

Aby rozwiązać ten problem, należy zdefiniować dodatkowo:

spellWord([]). 

Jest to krótka forma:

spellWord(String) :- String = []. 

Twoje inne orzeczenie ma również problemu:

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

Masz dwie zmienne tutaj, String i. Te zmienne nie są w żaden sposób powiązane. Więc bez względu na to, co przekazujesz jako parametr, nie wpłynie to na H, którego używasz do porównania. A ponieważ operator == dokonuje jedynie porównania, bez unifikacji, w tym momencie kończy się niepowodzeniem writeChar, zwracając false. To jest powód, dla którego nie ma żadnego wyjścia.

+1

Nadal występuje problem z tym, co nazywasz ciągiem i czy jest to lista. Jeśli po prostu zainstalujesz najnowszy SWI-Prolog i wpiszesz ciąg znaków między podwójnymi cudzysłowami, tak jak w '' foo "', to zdecydowanie zdecydowanie nie jest to lista, ale obiekt atomowy. –

+1

PS. Nawet jeśli predykat 'spellWord/1' nie powiedzie się, powinien wydrukować każdy element listy. Tak więc, w pewnym sensie robi to, co zamierzał zrobić. –