siempre - prolog ejemplos
Prólogo: combinando gramáticas DCG con otras restricciones (2)
bueno, siempre puedes usar {} y escribir cualquier tipo de predicado de prólogo en el medio, por ejemplo:
foo(X)-->
{ valid(X) },
[a].
foo(X)-->
[b].
para que pueda agregar algún tipo de contador de palabras. por supuesto, si cada token es una palabra, simplemente podría escribir algo como: length (L, N), N <11, start (L, []).
por otro lado, quizás sea mejor, dependiendo de la complejidad de las restricciones, codificarlas en una parte diferente. algo así como analizador semántico analizador en compiladores.
Estoy muy impresionado con el DCG de Prolog y con la rapidez con la que puedo producir todas las estructuras posibles que se ajustan a una gramática en particular.
Pero me gustaría combinar esta búsqueda con otras restricciones. Por ejemplo, defina una gramática compleja y pida a Prolog que genere todas las oraciones con no más de 10 palabras. O todas las oraciones que no repiten la misma palabra dos veces.
¿Es posible agregar restricciones adicionales como esta a una gramática DCG? ¿O básicamente tengo que traducir el DCG a las cláusulas de Prolog normales y comenzar a modificarlas?
Si solo desea ver todas las oraciones que se generan, es muy conveniente usar lo siguiente:
?- length(Xs, N), phrase(mynonterminal, Xs).
Por supuesto, eso genera todas las oraciones. Pero es muy útil y te ahorra tiempo para pensar en un límite concreto. Si desea restringirlo más, agregue el objetivo between(0,10,N)
al frente.
Si desea decir dentro de una gramática, que un cierto no terminal debe tomar una cierta duración, lo mejor es decir esto de manera explícita:
seq([]) --> [].
seq([E|Es]) --> [E], seq(Es).
a --> {length(Es,10)}, seq(Es), {phrase(mynonterminal,Es)}.
Si todavía no está satisfecho, entonces quiere expresar la intersección de dos terminales. Esto es equivalente a pedir la intersección de dos lenguajes libres de contexto que, en el caso general, es indecidible. Pero mucho antes, tendrá problemas con la terminación. Así que ten cuidado de eso en lo que sigue:
:- op( 950, xfx, &).
(NT1 & NT2) -->
call(Xs0^Xs^(phrase(NT1,Xs0,Xs),phrase(NT2,Xs0,Xs))).
Lo siguiente solo es necesario si no usa la biblioteca (lambda) :
^(V0, Goal, V0, V) :-
call(Goal,V).
^(V, Goal, V) :-
call(Goal).
Esto le permite ahora expresar la intersección de dos terminales. Pero, por favor, tenga en cuenta que la terminación es muy frágil aquí. En particular, la terminación del primer no terminal no necesariamente limita el segundo.