Introdución al procesamiento del lenguaje natural en PROLOG

20
Prolog 1 Introdución al procesamiento del lenguaje natural en PROLOG Jorge Cabrera Gámez Departamento de Informática y Sistemas Universidad de Las Palmas de Gran Canaria

description

Introdución al procesamiento del lenguaje natural en PROLOG. Jorge Cabrera Gámez Departamento de Informática y Sistemas Universidad de Las Palmas de Gran Canaria. Procesamiento del lenguaje natural en Prolog. - PowerPoint PPT Presentation

Transcript of Introdución al procesamiento del lenguaje natural en PROLOG

Page 1: Introdución al procesamiento del lenguaje natural en PROLOG

Prolog 1

Introdución al

procesamiento del

lenguaje natural en

PROLOG

Jorge Cabrera GámezDepartamento de Informática y Sistemas

Universidad de Las Palmas de Gran Canaria

Page 2: Introdución al procesamiento del lenguaje natural en PROLOG

Prolog 2

Procesamiento del lenguaje natural en Prolog

Prolog ofrece algunas facilidades para definir analizadores gramaticales y, en general, para diseñar sistemas orientados al procesamiento del lenguaje natural.

Supongamos que necesitamos definir un programa que sea capaz de aceptar frases como:

• Mi abuelo come papaya.• El coche rojo es muy veloz.• Tu hermano es el hijo de tus padres• Tu abuelo es el padre de tus padres• Mi primo es el hijo de mis tíos

Page 3: Introdución al procesamiento del lenguaje natural en PROLOG

Prolog 3

Procesamiento del lenguaje natural en Prolog

• Tu hermano es el hijo de tus padres• Tu abuelo es el padre de tus padres• Mi primo es el hijo de mis tíos

Estas frases se ajustan a la siguiente gramática BNF:

<frase>::= <sn> <sv><sn>::= <adjetivo> <nombre> | <determinante> <nombre><sv>::= <verbo> <atributo><atributo>::= <sn> <cn><adjetivo>::= tu | mi | mis | tus<nombre>::= hermano | abuelo | primo | padres | tíos | hijo | padre<verbo>::= es<determinante>::= el<cn>::= <prep> <sn><prep>::= de

Page 4: Introdución al procesamiento del lenguaje natural en PROLOG

Prolog 4

<frase>::= <sn> <sv><sn>::= <adjetivo> <nombre> | <determinante> <nombre><sv>::= <verbo> <atributo><atributo>::= <sn> <cn><adjetivo>::= tu | mi | mis | tus<nombre>::= hermano | abuelo | primo | padres | tíos | hijo | padre<verbo>::= es<determinante>::= el<cn>::= <prep> <sn><prep>::= de

frase(L):-append(SN,SV,L),sn(SN),sv(SV).

La idea es escribir un programa que acepte una frase si se adecúa a las reglas de la gramática o la rechace en caso contrario.

La frase en cuestión se presentará como una lista de palabras, p.e.:?- frase([mi,primo,es,el,hijo,de,mis,tíos]).

Una forma de implementar estas reglas gramaticales es emplear una estrategia de “generación_y_test” como muestra el siguiente ejemplo:

Page 5: Introdución al procesamiento del lenguaje natural en PROLOG

Prolog 5

sv(SV):- append(SVA,SVB,SV),verbo(SVA),atributo(SVB).

atributo(SA):-append(SN,CN,SA),sn(SN),cn(CN).

cn(SV):- append(P,SN,SV),prep(P),sn(SN).

adjetivo([mi]).adjetivo([mis]).adjetivo([tu]).adjetivo([tus]).

nombre([hermano]).nombre([abuelo]).nombre([primo]).nombre([padres]).nombre([tíos]).nombre([hijo]).nombre([padre]).

verbo([es]).

determinante([el]).

prep([de]).

<frase>::= <sn> <sv><sn>::= <adjetivo> <nombre> | <determinante> <nombre><sv>::= <verbo> <atributo><atributo>::= <sn> <cn><adjetivo>::= tu | mi | mis | tus<nombre>::= hermano | abuelo | primo | padres | tíos | hijo | padre<verbo>::= es<determinante>::= el<cn>::= <prep> <sn><prep>::= de

frase(L):- append(SN,SV,L),sn(SN),sv(SV).

sn(SN):- append(SNA,SNB,SN),adjetivo(SNA),nombre(SNB).

sn(SN):- append(SNA,SNB,SN),determinante(SNA),nombre(SNB).

Page 6: Introdución al procesamiento del lenguaje natural en PROLOG

Prolog 6

Listas “diferencia”

Se denominan “listas diferencia” (difference lists) a una forma de representar listas en Prolog que - como técnica de programación - puede provocar un notable incremento de eficiencia.Ejemplo: Supongamos que deseamos diseñar un procedimiento que nos permita añadir un elemento a una lista por la cabeza.

add_to_head(X,Ys,[X|Ys]).

Esto es fácil. Supongamos ahora que deseamos diseñar el procedimiento complementario add_to_back.

Page 7: Introdución al procesamiento del lenguaje natural en PROLOG

Prolog 7

Ejemplo (cont): Realmente no es muy difícil ...

add_to_back(X, [ ], [X]).add_to_back(X, [Y|Ys], [Y|Zs]):-

add_to_back(X,Ys,Zs).

Sin embargo, es terriblemente ineficiente por motivos evidentes.

Ejemplo: Algo similar ocurre con la definición estándar de append/3:

append([ ], Ys, Ys).append([X|Xs], Ys, [X|Zs]):-

append(Xs,Ys,Zs).

Page 8: Introdución al procesamiento del lenguaje natural en PROLOG

Prolog 8

Las listas diferencia permiten manipular listas de forma mucho más eficiente definiendo “patrones de listas”.

Por ejemplo:

difference_append (A-Z, Z-B, A-B).

?- difference_append([a,b,c], [d,e], R).No.

?- difference_append([a,b,c]-Z, Z-[d,e], R).Z = _G379R = [a, b, c]-[d, e]

Yes

?- difference_append([a,b,c|Z] - Z, [d,e] - [ ], R).Z = [d, e]R = [a, b, c, d, e] - [ ] Yes

?- difference_append([a,b,c|Z] - Z, [d,e] - [ ], R- [ ]).

Z = [d, e]R = [a, b, c, d, e]

Yes

Page 9: Introdución al procesamiento del lenguaje natural en PROLOG

Prolog 9

Las siguientes definiciones transforman una lista diferencia en una lista“normal”, pero no a la inversa

dl_to_list([ ] - _, [ ]) :- !.dl_to_list([X|Y] - Z, [X|W]) :- dl_to_list(Y - Z, W).

?- dl_to_list([1,2,3|X]-X,L).X = [ ]L = [1,2,3];No

Recíprocamente, list_to_dl transforma una lista “normal” en una lista diferencia, pero no a la inversa

list_to_dl([], X - X).list_to_dl([X|W], [X|Y] - Z) :- list_to_dl(W, Y - Z).

?- list_to_dl([a,b,c],Y-Z).Y = [a, b, c|_G167]Z = _G167 ;No

Page 10: Introdución al procesamiento del lenguaje natural en PROLOG

Prolog 10

Listas Diferencia

El problema con esta estrategia es que es terriblemente ineficaz como puede comprobarse fácilmente realizando una traza de la anterior definición de frase/1.

La estrategia más eficiente es evitar la etapa de generación y pasar la lista completa a los predicados que implementan las reglas gramaticales. Éstos identificarán los correspondientes elementos gramaticales procesando secuencialmente los elementos de la lista de izquierda a derecha, devolviendo el resto de la lista.

Para hacer esto podemos emplear listas diferencia como se ilustra en la siguiente versión del analizador gramatical del ejemplo anterior.

Page 11: Introdución al procesamiento del lenguaje natural en PROLOG

Prolog 11

sv(SV-R):- verbo(SV-SV1),atributo(SV1-R).

atributo(SA-R):-sn(SA-SA1),cn(SA1-R).

cn(SV-R):- prep(SV-SV1),sn(SV1-R).

adjetivo([mi|X]-X).adjetivo([mis|X]-X).adjetivo([tu|X]-X).adjetivo([tus|X]-X).

nombre([hermano|X]-X).nombre([abuelo|X]-X).nombre([primo|X]-X).nombre([padres|X]-X).nombre([tíos|X]-X).nombre([hijo|X]-X).nombre([padre|X]-X).

verbo([es|X]-X).determinante([el|X]-X).prep([de|X]-X).

<frase>::= <sn> <sv><sn>::= <adjetivo> <nombre> | <determinante> <nombre><sv>::= <verbo> <atributo><atributo>::= <sn> <cn><adjetivo>::= tu | mi | mis | tus<nombre>::= hermano | abuelo | primo | padres | tíos | hijo | padre<verbo>::= es<determinante>::= el<cn>::= <prep> <sn><prep>::= de

frase(S):-sn(S-S1),sv(S1-[]).

sn(SN-R):-adjetivo(SN-SN1),nombre(SN1-R).

sn(SN-R):-determinante(SN-SN1),nombre(SN1-R).

Page 12: Introdución al procesamiento del lenguaje natural en PROLOG

Prolog 12

sv(SV-R):- verbo(SV-SV1),atributo(SV1-R).

atributo(SA-R):-sn(SA-SA1),cn(SA1-R).

cn(SV-R):- prep(SV-SV1),sn(SV1-R).

adjetivo([mi|X]-X).adjetivo([mis|X]-X).adjetivo([tu|X]-X).adjetivo([tus|X]-X).

nombre([hermano|X]-X).nombre([abuelo|X]-X).nombre([primo|X]-X).nombre([padres|X]-X).nombre([tíos|X]-X).nombre([hijo|X]-X).nombre([padre|X]-X).

verbo([es|X]-X).determinante([el|X]-X).prep([de|X]-X).

?- nombre([hijo,de,mis,tíos] - X).X = [de, mis, tíos] Yes

?- sn([mi,abuelo,es,el,padre,de,mi,padre] - X).X = [es, el, padre, de, mi, padre] Yes

frase(S):-sn(S-S1),sv(S1-[ ]).

sn(SN-R):-adjetivo(SN-SN1),nombre(SN1-R).

sn(SN-R):-determinante(SN-SN1),nombre(SN1-R).

Page 13: Introdución al procesamiento del lenguaje natural en PROLOG

Prolog 13

Gramática Definida por Cláusulas

La mayoría de las implementaciones de Prolog incorporan la posibilidad de definir gramáticas mediante una sintaxis especial que oculta la presencia de las listas diferencia. A esta sintaxis se le conoce como gramática definida por cláusulas (Definite Clause Grammar, DCG).

frase --> sn, sv.

sn --> adjetivo, nombre.sn --> determinante, nombre.

sv --> verbo, atributo.atributo --> sn, cn.cn --> prep, sn.

adjetivo --> [mi].adjetivo --> [mis].adjetivo --> [tu].adjetivo --> [tus].

nombre --> [hermano].nombre --> [abuelo].nombre --> [primo].nombre --> [padres].nombre --> [tíos].nombre --> [hijo].nombre --> [padre].

verbo --> [es].determinante --> [el].prep --> [de].

Page 14: Introdución al procesamiento del lenguaje natural en PROLOG

Prolog 14

Gramática de Cláusulas Definidas

Las cláusulas gramaticales así definidas se analizan y “traducen” en cláusulas Prolog que emplean listas diferencias. Por ejemplo, la primera de las reglas:

frase --> sn, sv.

se traduce en:frase(A, B) :- sn(A, C), sv(C, B).

Así que para analizar una frase, hemos de invocar frase/2 con dos argumentos:

?- frase([mi,abuelo,es,el,padre,de,mi,padre],R).R = [] Yes

Evidentemente , el segundo argumento “recogerá” el resto “inaceptado” de la frase cuando éste exista.

Page 15: Introdución al procesamiento del lenguaje natural en PROLOG

Prolog 15

Gramática de Cláusulas Definidas

Las cláusulas gramaticales que recogen los símbolos terminales, el vocabulario, se traducen también en listas diferencias. Por ejemplo:

adjetivo --> [mi].

se traduce en:adjetivo([mi|A],A).

La gramática que hemos definido presenta algunas deficiencias como la falta de concordancia entre el número del adjetivo y el nombre. Por ejemplo, “mi padres” resultaría aceptable como sintagma nominal (sn):

?- sn([mi,padres], R).R = [] Yes

Por ello una frase como la siguiente sería aceptable:

?- frase([mi,abuelo,es,el,padres,de,mis,padre],R).R = [] Yes

Page 16: Introdución al procesamiento del lenguaje natural en PROLOG

Prolog 16

Uso de Variables en DCGs

Para resolver este problema podemos emplear argumentos en las cláusulas de la gramática como se muestra a continuación:

frase --> sn, sv.sn --> adjetivo(N), nombre(N).sn --> determinante(N), nombre(N).sv --> verbo, atributo.atributo --> sn, cn.cn --> prep, sn.

adjetivo(sing) --> [mi].adjetivo(plur) --> [mis].adjetivo(sing) --> [tu].adjetivo(plur) --> [tus].

nombre(sing) --> [hermano].nombre(sing) --> [abuelo].nombre(sing) --> [primo].nombre(plur) --> [padres].nombre(plur) --> [tíos].nombre(sing) --> [hijo].nombre(sing) --> [padre].

verbo --> [es].determinante(sing) --> [el].prep --> [de].

Ahora una frase como:

?- frase([mi,primo,es,el,hijo,de,mi,tíos],R).No

ya no resulta aceptable

Page 17: Introdución al procesamiento del lenguaje natural en PROLOG

Prolog 17

Uso de Variables en DCGs

El uso de variables no está restringido al cuerpo de las reglas. Así la versión de la gramática que se muestra en la siguiente diapositiva usa variables para devolver un análisis sintáctico (y eventualmente morfológico) de la frase.

Por ejemplo (ligeramente retocado):

?- frase(S,[mi,primo,es,el,hijo,de,mis,tíos],[]).

S = análisis( sn(adj(mi), nom(primo)), sv(v(es), atrib(sn(det(el), nom(hijo)), cn(prep(de), sn(adj(mis), nom(tíos))))))

Yes

Page 18: Introdución al procesamiento del lenguaje natural en PROLOG

Prolog 18

frase(análisis(S,V)) --> sn(S), sv(V).sn(sn(A,B)) --> adjetivo(A,N), nombre(B,N).sn(sn(A,B)) --> determinante(A,N), nombre(B,N).sv(sv(V,A)) --> verbo(V), atributo(A).atributo(atrib(S,C)) --> sn(S), cn(C).cn(cn(P,S)) --> prep(P), sn(S).

adjetivo(adj(mi),sing) --> [mi].adjetivo(adj(mis),plur) --> [mis].adjetivo(adj(tu),sing) --> [tu].adjetivo(adj(tus),plur) --> [tus].

nombre(nom(hermano),sing) --> [hermano].nombre(nom(abuelo),sing) --> [abuelo].nombre(nom(primo),sing) --> [primo].nombre(nom(padres),plur) --> [padres].nombre(nom(tíos),plur) --> [tíos].nombre(nom(hijo),sing) --> [hijo].nombre(nom(padre),sing) --> [padre].

verbo(v(es)) --> [es].determinante(det(el),sing) --> [el].prep(prep(de)) --> [de].

Page 19: Introdución al procesamiento del lenguaje natural en PROLOG

Prolog 19

Es posible incluir cláusulas “prolog” en la definición de las cláusulas gramaticales. Las cláusulas “prolog” deben encerrarse entre llaves { }, como se muestra en el siguiente ejemplo, donde se han agrupado las definiciones de los adjetivos en la gramática que se ha venido usando como ejemplo (exactamente lo mismo puede hacerse con los nombres):adjetivo(adj(X),sing) --> [X],{ member(X,[mi,tu]) }.adjetivo(adj(X),plural) --> [X], { concat_atom([Y,s],X),

adjetivo(adj(Y),sing,[Y],[])}.

?- listing(adjetivo).

adjetivo(adj(A), sing, B, C) :- 'C'(B, A, D), member(A, [mi, tu]), C=D.adjetivo(adj(A), plural, B, C) :- 'C'(B, A, D), concat_atom([E, s], A), adjetivo(adj(E), sing, [E], []), C=D.Yes

Page 20: Introdución al procesamiento del lenguaje natural en PROLOG

Prolog 20

frase(análisis(S,V)) --> sn(S), sv(V).sn(sn(A,B)) --> adjetivo(A,N), nombre(B,N).sn(sn(A,B)) --> determinante(A,N), nombre(B,N).sv(sv(V,A)) --> verbo(V), atributo(A).atributo(atrib(S,C)) --> sn(S), cn(C).cn(cn(P,S)) --> prep(P), sn(S).

adjetivo(adj(X),sing) --> [X],{ member(X,[mi,tu]) }.

adjetivo(adj(X),plural) --> [X], { concat_atom([Y,s],X), adjetivo(adj(Y),sing,[Y],[])}.

nombre(nom(X),sing) --> [X], { member(X,[abuelo,hermano,padre, primo,tío,hijo]) }.

nombre(nom(X),plural) --> [X], { concat_atom([Y,s],X), nombre(nom(Y),sing,[Y],[])}.

verbo(v(es)) --> [es].determinante(det(el),sing) --> [el].prep(prep(de)) --> [de].