Listing come fatti
Proviamo a spiegare questo con un controesempio. Diamo specificare i nomi, verbi, ecc, con semplici fatti:
det(the).
det(a).
n(woman).
n(man).
v(shoots).
Ora possiamo implementare una sostantivo frasenp
come:
np([X,Y]) :-
det(X),
n(Y).
In altre parole si dice "una frase sostantivo è un frase con due parole, la prima è una det
, la seconda una n
". E questo funzionerà: se interrogiamo np([a,woman])
, avrà successo ecc.
Ma ora dobbiamo fare qualcosa di più avanzato, definire la frase del verbo.Ci sono due possibili sintagmi verbali: quello con un verbo e un sintagma nominale che è stato originariamente definito come:
vp(X,Z):- v(X,Y),np(Y,Z).
potremmo definire come:
vp([X|Y]) :-
v(X),
np(Y).
E quella con un solo verbo :
vp(X,Z):- v(X,Z).
che può essere convertito in:
vp([X]) :-
v(X).
Il problema di indovinatura
Il problema tuttavia è che entrambe le varianti hanno un numero diverso di parole: ci sono frasi verbali con una parola e con tre parole. Questo non è davvero un problema, ma ora dicono - so che questo non è corretto Inglese - esiste una sentenza definita come vp
seguita da np
, quindi questo sarebbe:
s(X,Z):- vp(X,Y), np(Y,Z).
nella grammatica originale.
Il problema è che, se vogliamo trasformare questo nel nostro nuovo modo di rappresentarla, abbiamo bisogno di sapere quanto sarà vp
consumare (quanto parole sarà mangiato da vp
). Non possiamo saperlo in anticipo: dato che a questo punto non sappiamo molto della frase, non possiamo indovinare se lo vp
mangerà una o tre parole.
potremmo naturalmente indovinare il numero di parole con:
s([X|Y]) :-
vp([X]),
np(Y).
s([X,Y,Z|T]) :-
vp([X,Y,Z]),
np(Z).
Ma spero che si può immaginare che se si definirebbe sintagmi verbali con 1, 3, 5 e 7 parole, le cose andranno problematico. Un altro modo per risolvere questo problema, è lasciare che questo Prolog:
s(S) :-
append(VP,NP,S),
vp(VP),
np(NP).
Ora Prolog indovinare come suddividere la frase in due parti prima e poi cercare di soddisfare ogni sua parte. Ma il problema è che per una frase con n parole, ci sono n punti di interruzione.
Così Prolog volontà, per esempio prima divisione come:
VP=[],NP=[shoots,the,man,the,woman]
(ricordiamo abbiamo scambiato l'ordine del verbo frase e la frase sostantivo). Evidentemente il numero vp
non sarà molto felice se riceverà una stringa vuota. Così sarà respinto facilmente. Ma la prossima si dice:
VP=[shoots],NP=[the,man,the,woman]
Ora vp
è felice con solo shoots
, ma richiederà un certo sforzo computazionale per rendersi conto che. np
non è tuttavia divertito da questa lunga parte. Così Prolog marcia indietro di nuovo:
VP=[shoots,the],NP=[man,the,woman]
ora vp
si lamentano ancora una volta che è stato dato troppo parole.Finalmente Prolog lo dividerà correttamente con:
VP=[shoots,the,woman],NP=[the,woman]
Il punto è che richiede un gran numero di ipotesi. E per ognuna di queste ipotesi, vp
e np
richiederanno anche il lavoro. Per una grammatica veramente complicata, vp
e np
potrebbero dividere ulteriormente la frase, con conseguente enorme quantità di tentativi ed errori.
Il vero motivo è che lo append/3
non ha indizi "semantici" su come suddividere la frase, quindi tenta tutte le possibilità. Uno è tuttavia più interessato ad un approccio in cui vp
potrebbe fornire informazioni su quale parte della frase desidera realmente.
Inoltre, se è necessario dividere la frase in 3 parti, il numero di modi per farlo aumenta anche a O (n^2) e così via. Quindi indovinare non farà il trucco.
Si potrebbe anche provare a generare una frase di verbo a caso, e poi sperare la frase verbo corrisponde:
s(S) :-
vp(VP),
append(VP,NP,S),
np(NP).
Ma in questo caso il numero di sintagmi verbali indovinati si saltare in aria in modo esponenziale. Naturalmente puoi dare "suggerimenti" ecc. Per accelerare il processo, ma ci vorrà ancora del tempo.
La soluzione
Che cosa si vuole fare è quello di fornire la parte della frase ad ogni predicato in modo tale che un predicato assomiglia:
predicate(Subsentence,Remaining)
Subsentence
è una lista di parole che iniziano per che predicato. Ad esempio per una frase nominale, potrebbe apparire come [the,woman,shoots,the,man]
. Ogni predicato consuma le parole a cui è interessato: le parole fino a un certo punto. In questo caso, la frase-nome è interessata solo a ['the','woman']
, perché quella è una frase-nome. Per fare il parsing rimanente, restituisce la parte restante [shoots,the,woman]
, nella speranza che qualche altro predicato possa consumare il resto della frase.
per il nostro tavolo di fatti che è facile:
det([the|W],W).
det([a|W],W).
n([woman|W],W).
n([man|W],W).
v([shoots|W],W).
Ciò significa quindi che se si interroga un setence: [the,woman,shoots,...]
, e si chiede al det/2
che sia un determinante, si dirà: "Sì, the
è un determinante, ma la parte restante [woman,shoots,...]
"non fa parte del determinatore, si prega di abbinarlo con qualcos'altro.
Questa corrispondenza viene eseguita perché un elenco è rappresentato come un elenco collegato. [the,woman,shoots,...]
, in realtà è rappresentato come [the|[woman|[shoots|...]]]
(quindi punta al successivo "Sottolista"). Se corrispondono:
[the|[woman|[shoots|...]]]
det([the|W] ,W)
Sarà unificare [woman|[shoots|...]]
con W
e quindi provocare:
det([the|[woman|[shoots|...]],[woman|[shoots|...]]).
Così la restituzione del restante lista, ha così consumato la parte the
.livello
superiore predicati
Ora nel caso in cui definiamo il sostantivo frase:
np(X,Z):- det(X,Y), n(Y,Z).
E noi ancora una volta chiamata con [the,woman,shoots,...]
, si interrogherà unificante X
con quella lista. Chiamerà per prima cosa det
che consumerà the
, senza bisogno di backtracking. Successivo Y
è uguale a [woman,shoots,...]
, ora il n/2
consuma donna e restituisce [shoots,...]
. Questo è anche il risultato che lo np
restituirà e un altro predicato dovrà consumarlo.
utilità
Di 'si introduce il vostro nome come un sostantivo aggiuntivo:
n([doug,smith|W],W).
(scusate per l'utilizzo di piccoli casi, ma per il resto Prolog vede questi come variabili).
Si cercherà semplicemente di abbinare le prime due parole con doug
e smith
, e se ciò riesce, provare a far corrispondere il resto della frase. Quindi si può creare una serie come: [the,doug,smith,shoots,the,woman]
(mi dispiace per il fatto che, in inglese, alcune frasi nominali si associano ad un nome direttamente np(X,Y) :- n(X,Y)
così che lo the
possa essere rimosso per una grammatica inglese più complessa).
Indovinare completamente eliminato?
L'ipotesi è completamente eliminata? No. È ancora possibile che ci sia una sovrapposizione nel consumo. Per esempio si potrebbe aggiungere:
n([doug,smith|W],W).
n([doug|W],W).
In tal caso, se si esegue una query per [the,doug,smith,shoots,the,woman]
. In primo luogo consumerà/mangi il det
, successivamente cercherà un nome da consumare da [doug,smith,...]
. Ci sono due candidati. Prolog prima tenterà di mangiare solo doug
e corrisponderà a [smith,shoots,...]
come una frase intera di un verbo, ma poiché smith
non è un verbo, tornerà indietro, riconsidererà solo una parola e quindi decinderà di mangiare sia doug
che smith
come nome.
Il punto è che quando si utilizza append, Prolog dovrebbe tornare indietro.
Conclusione
Utilizzando gli elenchi di differenza, si può mangiare una quantità arbitraria di parole. Il resto viene restituito in modo che altre parti della frase come la frase del verbo mirino a consumare il resto. L'elenco è inoltre sempre completamente fondato, quindi non si usa assolutamente la forza bruta per generare prima tutti i tipi di frasi verbali.
Il visualizzatore dice che una query è previsto. Hai inserito una query quando hai inserito quel codice? Il codice non contiene la query. Devi rilasciare la query. Ad esempio, dopo aver inserito il codice, puoi provare la query 's ([a, woman, shoots, a, man], X)?' – lurker
Se vuoi generare tutte le frasi riconosciute, inserisci il codice che hai elencato, e interrogare, 's (Frase, []).' al prompt di Prolog (o 's (Sentence, [])?' nel visualizzatore). – lurker
Tbh questa è una spiegazione molto interessante degli elenchi di differenze – vmg