2016-05-22 1 views
0

J'essaye d'écrire un DCG pour une interface de commande. L'idée est de lire une chaîne d'entrée, de la diviser en espaces, et de transmettre la liste de jetons qui en résulte à un DCG pour l'analyser en une commande et des arguments. Le résultat de l'analyse devrait être une liste de termes que je peux utiliser avec =.. pour construire un objectif à appeler. Cependant, je suis devenu vraiment confus par la situation du type de chaîne dans SWI-Prolog (voir 7.2.3). SWI-Prolog inclut une bibliothèque de basic DCG functionality, incluant un objectif integer//1 qui est supposé analyser un entier. Il échoue en raison d'une erreur de type, mais le plus gros problème est que je n'arrive pas à comprendre comment faire fonctionner correctement un DCG dans SWI-Prolog avec des "listes de jetons".Erreurs de type Prolog avec fonctions de bibliothèque DCG

Voici ce que je suis en train de faire:

:- use_module(library(dcg/basics)). 

% integer//1 is from the dcg/basics lib 
amount(X) --> integer(X), { X > 0 }. 
cmd([show,all]) --> ["show"],["all"]. 
cmd([show,false]) --> ["show"]. 
cmd([skip,X]) --> ["skip"], amount(X). 

% now in the interpreter: 
?- phrase(cmd(L), ["show","all"]). 
L = [show, all]. 
% what is the problem with this next query? 
?- phrase(cmd(L), ["skip", "50"]). 
ERROR: code_type/2: Type error: `character' expected, found `"50"' (a string) 

J'ai lu Section 5.2 du manuel SWI, mais cela n'a pas tout à fait répondre à mes questions:

  1. Quel type est attendu par integer//1 dans la bibliothèque dcg/basics? Le message d'erreur dit "caractère", mais je ne trouve aucune référence utile quant à ce que cela signifie exactement et comment lui fournir une entrée "correcte".
  2. Comment puis-je transmettre une liste de chaînes (jetons) à phrase/2 afin que je puisse utiliser integer//1 pour analyser un jeton comme un entier?
  3. S'il n'y a aucun moyen d'utiliser la primitive integer//1 pour analyser une chaîne de chiffres en entier, comment dois-je accomplir cela?

je l'ai fait un peu de expermenting avec l'aide des valeurs différentes pour le drapeau double_quote dans SWI-Prolog, plus différents formats d'entrée, comme l'utilisation d'une liste d'atomes, en utilisant une seule chaîne comme l'entrée, à savoir "skip 50" plutôt que ["skip", "50"], et ainsi de suite, mais j'ai l'impression qu'il existe des hypothèses sur le fonctionnement des DCG que je ne comprends pas.

J'ai étudié ces trois pages et qui ont beaucoup d'exemples, mais pas tout à fait mes questions portent sur (certains liens omis depuis que je n'ai pas assez réputation d'afficher tous):

  1. Le tutoriel "Utilisation de grammaires à clauses définies dans SWI-Prolog" par Anne Ogborn
  2. Un tutoriel d'Amzi! Prologue sur l'écriture d'interfaces de commande en tant que DCG.
  3. Section 7.3 du tutoriel de JR Fisher Prolog

Une troisième question plus large est de savoir comment générer un message d'erreur si un entier est prévu, mais ne peut pas être analysé comme un, quelque chose comme ceci:

% the user types: 
> skip 50x 
I didn't understand that number. 

Une approche consiste à définir la variable X dans le DCG ci-dessus à une sorte de valeur d'erreur, puis de vérifier cela plus tard (comme dans le but hypothétique skip/1 qui est censé être appelé par la commande), mais peut-être manière plus idiomatique? La plus grande partie de mon expérience dans l'écriture d'analyseurs vient de l'utilisation des bibliothèques Parsec et Attoparsec de Haskell, qui sont assez déclaratives mais qui fonctionnent un peu différemment, en particulier en ce qui concerne la gestion des erreurs.

+0

Comment est 'integer' défini dans votre DCG? – lurker

+0

Cela fait partie d'une bibliothèque livrée avec SWI-Prolog, documentée [ici] (http://www.swi-prolog.org/pldoc/doc/swi/library/dcg/basics.pl). Je vais modifier le post avec cette information. – DCE

+0

Ce prédicat ('entier (X)') nécessite un argument entier, selon la documentation, mais vous essayez d'analyser un atome (''50 '') avec lui (je suppose que votre prologue SWI est configuré pour interpréter' " 50 "' comme l'atome '' 50''). – lurker

Répondre

0

Prolog ne possède pas de chaînes. La représentation traditionnelle d'une séquence de caractères à guillemets doubles est une liste de codes (entiers). Pour efficiency reasons, SWI-Prolog ver.> = 7 cordes introduites comme nouveau atomique type de données:

?- atomic("a string"). 
true. 

et littéraux backquoted ont maintenant le rôle précédemment tenu par des cordes:

?- X=`123`. 
X = [49, 50, 51]. 

Inutile de dire que cela a causé some confusion, également compte tenu de la De plus, un DCG fonctionne toujours sur des listes (de différences) de codes de caractères, juste le traducteur a été étendu pour accepter les chaînes comme des terminaux. Votre code pourrait être

cmd([show,all]) --> whites,"show",whites,"all",blanks_to_nl. 
cmd([show,false]) --> whites,"show",blanks_to_nl. 
cmd([skip,X]) --> whites,"skip",whites,amount(X),blanks_to_nl. 

et peut être appelé comme

?- phrase(cmd(C), ` skip 2300 `). 
C = [skip, 2300]. 

modifier

comment générer un message d'erreur si un entier est prévu

I essayerait:

... 
cmd([skip,X]) --> whites,"skip",whites,amount(X). 

% integer//1 is from the dcg/basics lib 
amount(X) --> integer(X), { X > 0 }, blanks_to_nl, !. 
amount(unknown) --> string(S), eos, {print_message(error, invalid_int_arg(S))}. 

prolog:message(invalid_int_arg(_)) --> ['I didn\'t understand that number.']. 

test:

?- phrase(cmd(C), ` skip 2300x `). 
ERROR: I didn't understand that number. 
C = [skip, unknown] ; 
false. 
+0

L'espace doit donc être inclus dans l'entrée de 'phrase/2'? J'espérais qu'il y avait un moyen de traiter une liste de jetons directement. Il semble qu'une partie du problème est que 'integer // 1' attend une liste de codes de caractères (comme" 123 "), mais obtient [" 123 "] (en supposant que les chaînes entre guillemets doubles produisent une liste de codes de caractères; est disponible comme drapeau dans SWI-Prolog 7). Est-ce exact? – DCE

+0

Oui, integer // 1 attend (ou génère) une liste de codes de caractères. En effet, pour un DCG simple, un jeton est juste un code de caractère. Pour convertir une chaîne en un nombre, vous pouvez utiliser '? - number_string (X," 123 ").'. Peut-être que le point qui me manque est: d'où viennent vos jetons, et pourquoi sont-ils des cordes? – CapelliC

+0

L'idée est de lire une ligne d'entrée à partir d'un flux, la diviser en jetons (par exemple "do this" -> ["faire", "this"]), puis le donner au DCG pour analyser une liste de termes . Cela semble naturel à faire avec les DCG, comme indiqué [ici] (http://www.amzi.com/manuals/amzi/pro/ref_dcg.htm#DCGCommandLanguage) et [ici] (http://www.cpp.edu /~jrfisher/www/prolog_tutorial/7_3.html). L'exemple précédent est dans Prolog Amzi mais est à peu près exactement ce que je veux faire, MAIS, je veux utiliser les primitives DCG de SWI-Prolog (comme 'integer // 1') pour aider si possible. Les types ne semblent pas fonctionner et je ne suis pas sûr de savoir comment réparer. – DCE