You are on page 1of 27

STEFANO FERILLI

Monografia su

SISTEMI ESPERTI
IN
PROLOG

Universit degli Studi di Bari


Facolt di Scienze Matematiche, Fisiche e Naturali
Corso di Laurea in Informatica

Corso di Ingegneria della Conoscenza e Sistemi Esperti

SISTEMI ESPERTI

Un sistema esperto un programma che si comporta come un esperto per un determinato


problema.
Esso in grado non solo di sfruttare una base di conoscenza sullo specifico dominio per
la risoluzione di problemi ad esso correlati, ma anche di esplicitare e spiegare le
decisioni prese ed il ragionamento sottostante.
I sistemi esperti possono essere usati per l'analisi (ossia per la classificazione) o per la
sintesi (ossia per la deduzione di nuova conoscenza a partire da quella gi posseduta).

Il loro schema generale il seguente:

Utente

Interfaccia
Utente

Motore
Inferenziale

Shell

Base di
Conoscenza

Tools per lo sviluppo


- Tipo Skeleton
Motore inferenziale e interfaccia presi da un sistema esperto gi esistente, cui stata
tolta la conoscenza specifica.
Pi immediati, meno flessibili.
- Tipo Environment
Ambienti general-purpose che consentono di creare l'interfaccia ed il meccanismo di
ragionamento.
Pi flessibili, ma anche pi complessi.

FASI NELLA COSTRUZIONE


DI UN SISTEMA ESPERTO

Rappresentazione della conoscenza


- Scegliere e definire i dettagli del formalismo
- Progettare i dettagli di un motore inferenziale che li sfrutti
- Aggiungere meccanismi per l'interazione con l'utente
- Aggiungere meccanismi per la gestione dell'incertezza

Motore inferenziale
- Definire il comportamento voluto
- Delineare il processo di ragionamento
- Rispondere a domande di tipo perch
- Rispondere a domande di tipo come

Implementazione
- Gestore (main):
expert
- Procedure principali:
explore (Goal, Trace, Answer)
useranswer (Goal, Trace, Answer)
present (Answer)

PROCESSO DI RAGIONAMENTO

Per trovare una risposta R ad una domanda D (che per semplicit supponiamo
ammettere come risposte Vero o Falso), usare il primo dei seguenti principi che risulti
applicabile:

- Se D si trova come fatto nella base di conoscenza, allora R "D vero".


- Se nella base di conoscenza c' una regola del tipo
se condizione allora D
allora controllare condizione e usare il risultato per costruire la risposta R alla
domanda D.
- Se D una domanda che si pu rivolgere all'utente, allora interrogare l'utente
riguardo a D.
- Se D della forma D1 e D2, allora esplorare D1 e quindi:
- se D1 falsa, allora R "D falsa",
- altrimenti esplorare D2 e combinare appropriatamente le risposte a D1 e D2 in R.
- Se D della forma D1 o D2, allora esplorare D1 e quindi:
- se D1 vera, allora R "D vera",
- altrimenti esplorare D2 e combinare appropriatamente le risposte a D1 e D2 in R.
- Se la domanda della forma non D, bisogna fare attenzione a come tale negazione
viene interpretata dal sistema, per evitare di ottenere risposte errate.

INTERAZIONE CON L'UTENTE

Il sistema deve interagire con l'utente sia per chiedere informazioni che non siano
5

ottenibili dalla base di conoscenza, sia per fornirgli spiegazioni sul proprio operato.

Richiesta di informazioni
Le richieste di informazioni dovrebbero essere fatte in modo tale da prevedere come
risposta un semplice si o no.
Esse dovrebbero anche essere strutturate in maniera che una risposta si faccia
continuare il sistema ad esaminare l'ipotesi corrente, mentre una risposta no causi
l'esplorazione di strade alternative.
E' possibile, all'inizio (ma non solo), presentare all'utente un questionario/menu
contenente un gruppo di domande di base o strettamente correlate fra loro, che possano
gi indirizzare il sistema verso un insieme di ipotesi piuttosto che verso un altro.

Domande di tipo perch


L'utente dovrebbe avere anche la possibilit, oltre a rispondere si o no, di chiedere al
sistema il perch di una certa domanda. Questo utile sia quando non chiaro il legame
che essa ha con il problema, sia quando rispondere comporterebbe un certo sforzo.
Minimalmente, il sistema dovrebbe prevedere una spiegazione ad hoc per ogni singola
domanda.
Questa soluzione, pi pratica per chi sviluppa il sistema, consente per solo spiegazioni
6

molto generiche quando una stessa domanda potrebbe essere fatta in momenti (e, quindi,
con scopi) diversi.
Una possibilit pi raffinata tenere traccia di tutto il processo di ragionamento che lega
la domanda attuale all'obiettivo originale, in modo da presentarlo come spiegazione
all'utente.
In tal caso, il sistema deve farsi carico di mantenere memoria di tutti i singoli passi di
ragionamento man mano che li esegue.

Domande di tipo come


Un altro tipo di spiegazione che il sistema dovrebbe essere in grado di dare , dopo aver
trovato una risposta al problema, spiegare il modo in cui vi giunto, affinch l'utente
possa controllarne la validit.
In tal caso va memorizzato non solo il legame di una singola domanda col problema
originale, ma tutto l'insieme di strade "confluenti" che hanno portato a quella
conclusione.

PROCEDURE DEL SISTEMA

Il main expert ha la funzione di leggere la domanda dell'utente, innescare il meccanismo


di ragionamento che trovi una risposta (positiva o negativa) a tale domanda e chiedere
7

all'utente se vuole conoscere altre possibili risposte, qualora ne esistano.


La procedura explore ha il compito di sfruttare la base di conoscenza alla ricerca di una
risposta alla domanda.
- Goal la domanda, rappresentata come combinazione di congiunzioni e/o
disgiunzioni di affermazioni semplici.
- Trace la catena di obiettivi e regole fra l'obiettivo attuale Goal e quello
iniziale, che consente di rispondere all'eventuale domanda dell'utente sul
perch si stia investigando l'obiettivo corrente.
- Answer la risposta all'obiettivo attuale Goal, sotto forma di albero di
dimostrazione, in modo da poterla giustificare ad un'eventuale domanda
dell'utente sul come il sistema vi sia giunto.
La procedura useranswer si incarica, qualora nella base di conoscenza del sistema non
esistano informazioni sufficienti per ottenere la risposta all'obiettivo attuale Goal, di
richiedere la risposta Answer direttamente all'utente, qualora ci sia possibile.
Essa (tramite l'argomento Trace) in grado di rispondere ad un'eventuale domanda
dell'utente sul perch della richiesta; cerca inoltre, per quanto possibile, di astrarre dalla
particolare espressione usata dall'utente.
Avendo gli stessi scopi della procedura explore, alla quale eseguita in alternativa, ha
anche gli stessi argomenti.
La procedura present, infine, si occupa di mostrare all'utente la risposta Answer alla sua
domanda iniziale, mostrandogli eventualmente anche come vi giunto.

INCERTEZZA

Il Prolog ha una natura categorica, nel senso che ogni elemento del ragionamento per
lui vero o falso, senza altra possibilit.
Ci sono, per, ambiti in cui non sempre possibile fare affermazioni categoriche, ma si
pu soltanto assegnare un certo grado di probabilit ad ogni fatto o regola che sia noto.

Tale concetto di probabilit, molto spesso, non va inteso nel senso matematico del
termine, ma piuttosto, in maniera intuitiva, come "fiducia soggettiva" che si ha nella
verit di un'affermazione o nel fatto che una regola di inferenza si riveli applicabile.
Per questo, nei sistemi esperti che trattano l'incertezza, non detto che il modello
implementato sia proprio quello matematico, ed anzi ancora oggetto di disputa il fatto
che sia pi opportuno usare la teoria delle probabilit "rigorosa" o una sua versione pi
informale e semplificata.
La teoria matematica ha dalla sua una maggiore fondatezza teorica, mentre i metodi
intuitivi poggiano sulla maggiore semplicit implementativa e computazionale oltre che
sulla somiglianza a quelli effettivamente usati dall'uomo.

E' possibile "cablare" nel Prolog il trattamento dell'incertezza, assegnando ad ogni


elemento di conoscenza un grado di probabilit e definendo le modalit con cui tali
9

probabilit si evolvono nel momento in cui vengono sfruttate dal processo di


ragionamento.

Per quanto riguarda i fatti, la relativa probabilit pu essere memorizzata sotto forma di
argomento aggiuntivo, mentre nelle regole si pu pensare di sfruttare un predicato
apposito, avente tale valore come argomento.
La probabilit degli elementi di conoscenza pu essere espressa tramite un numero finito
di descrittori, oppure numericamente entro una intervallo di valori prefissato, che pu
anche coincidere con il classico [0, 1].

Per quanto riguarda i meccanismi di combinazione delle probabilit fra fatti e regole, un
meccanismo molto semplice ma efficace potrebbe essere il seguente.
Denotiamo con c(X) la probabilit di una proposizione X, e supponiamo che sia un
numero reale compreso fra 0 e 1.
- Se P1 e P2 sono due fatti, con probabilit (rispettivamente) C1 e C2, allora:
c(P1 e P2) = min(c(P1),c(P2))
(significato intuitivo: se devono essere veri entrambi i fatti, allora la probabilit del risultato risentir
del pi debole)

c(P1 o P2) = max(c(P1),c(P2))


(significato intuitivo: se sufficiente che sia vero uno qualunque dei fatti, allora possiamo considerarli
interscambiabili e quindi associare al risultato la probabilit del pi forte)

c(non P1) = (1 - c(P1))


(significato intuitivo analogo a quello della teoria matematica: la probabilit dellopposto di un fatto
il complemento della probabilit del fatto stesso)
10

- Se c' una regola Se P1 allora P2 con probabilit C, allora:


c(P2) = c(P1) * C
(significato intuitivo: dopo aver assegnato una probabilit alla condizione in base alle sue singole
componenti, bisogna pesarla con quella della regola stessa per ottenere la probabilit della
conseguenza)

Questo schema , ovviamente, semplificato al massimo, perch sarebbe necessario


almeno prendere in considerazione anche le relazioni fra gli elementi di conoscenza, che
generalmente non sono indipendenti l'uno dall'altro.

Esiste un altro metodo per trattare l'incertezza, che, data un'ipotesi da verificare H e
dell'evidenza E raccolta per confermarla, modella la possibilit che E modifichi la
speranza in H tramite due parametri (invece che con un singolo valore di probabilit):
N = Fattore di Necessit
S = Fattore di Sufficienza
S ci dice quanto E sia sufficiente per H. Se E vero, tanto maggiore S tanto pi
probabile sar H.
N ci dice quanto E sia necessario per H. Se E falso, tanto pi basso N tanto meno
probabile sar H.
Se la probabilit di E a met strada fra la certezza e l'impossibilit, la probabilit di H
sar determinata per interpolazione fra i seguenti casi estremi:
11

- si sa che E falso
- si sa che E vero
- non si sa nulla di E.

Ogni evento H avr una probabilit a priori, che verr modificata man mano che nuova
conoscenza verr acquisita.

MODIFICA DELLE STRUTTURE DI


CONTROLLO DEL PROLOG

CICLO IBRIDO

Essendo un linguaggio general-purpose, il Prolog in grado di implementare anche


strutture di controllo differenti da quella standard (il backward chaining).
N.B.: Per semplicit, si supporr che le regole non contengano letterali negati.

12

Un primo tipo di controllo quello del ciclo di regole ibrido di backward e forward
chaining, pi semplice da implementare del forward puro.
Esso si ottiene trasformando ogni regola del programma nel seguente modo:
- aggiungere alla fine del corpo un letterale asserta() avente per argomento la
testa della regola stessa;
- aggiungere all'inizio del corpo un letterale not() con lo stesso argomento;
- sostituire la testa della regola con un nuovo predicato fittizio che non sia gi
stato usato dal programma (ad es., dummy).
Esempio.
Le regole

a :- b.

c :- d, e, f.

diventano, rispettivamente,
dummy :- not(a), b, asserta(a).

dummy :- not(c), d, e, f, asserta(c).

Poich tali regole non si richiamano mai a vicenda (nonostante l'esistenza di predicati
intermedi), necessario un main che le valuti tutte in sequenza, e ripeta tale operazione
fino al raggiungimento di una prefissata condizione di terminazione (tipicamente, la
soluzione del problema).

FORWARD CHAINING

Un altro meccanismo il forward chaining puro.


13

Poich esso lavora cercando ed eliminando progressivamente i letterali dei lati sinistri
delle regole che risultino veri come fatti della base di conoscenza, opportuno
trasformare testa e corpo di ogni regola in argomenti di un predicato fittizio rule (il
corpo, ovviamente, sar tradotto in una lista), ed esprimere ogni fatto sotto forma di
argomento di un predicato fittizio fact.
Questo consente di sfruttare le procedure Prolog member e delete.
Esempio.
Le regole

a :- b,c.

g(X) :- h(X,Y), not(f(Y)).

rule(g(X), [h(X,Y), not(f(Y))]).

diventano, rispettivamente,
rule(a, [b, c]).

Il main dovr quindi, ciclicamente: leggere un fatto, cancellarlo dal corpo di tutte le
regole che lo contengono e:
- qualora tutti i letterali del corpo siano stati cancellati
sostituire la regola con un nuovo fatto uguale alla sua testa
- o, altrimenti,
sostituire la nuova regola cos ottenuta alla precedente
fino a quando ci sia possibile.
Per evitare che un fatto usato venga ripreso in considerazione, verr eliminato non
appena usato e riasserito tramite un predicato fittizio usedfact.
Alla fine, tutte le conclusioni ottenute dalla base di conoscenze saranno sotto forma di
facts o di usedfacts.

14

EFFICIENZA

Un punto importante per il successo del sistema potrebbe rivelarsi l'efficienza, che pu
essere valutata da vari punti di vista, in corrispondenza dei quali richiede vari tipi di
soluzioni per essere raggiunta.

Indicizzazione dei predicati


Il Prolog indicizza automaticamente le clausole in base al predicato che compare nella
testa; a volte, per, potrebbe rivelarsi pi utile una suddivisione differente (ad es., nel
forward chaining, in base ai predicati che sono presenti nel corpo).
Si pu pensare ad un predicato fittizio rules, avente come primo argomento il valore
dell'indice e come secondo argomento la lista delle regole che condividono tale valore.
Lo svantaggio, in tal caso, la ridondanza derivante dal fatto che una stessa regola
potrebbe essere associata contemporaneamente a pi indici.

Meta-regole
Il Prolog usa le regole candidate in ordine di presentazione da parte del programmatore;
a volte, tuttavia, pi opportuno, sebbene ci comporti maggior perdita di tempo,
scegliere l'ordine con cui prendere in considerazione le regole in maniera pi ragionata.
Tale effetto pu essere ottenuto tramite un predicato prefer con quattro argomenti (la
15

testa ed il corpo di ciascuna delle due clausole da confrontare) che implementi la


funzione di valutazione scelta.

COMMENTI E SVILUPPI

- Mancanza di chiarezza dichiarativa


- Obiettivi negati
- Miglioramento:
- Obiettivi ciclici
- Navigazione nell'albero di dimostrazione
- Esplicitazione delle regole usate
- Miglioramento del dialogo con l'utente
- Ottimizzazione della ricerca (richieste-lunghezza)

UN ESEMPIO

Vediamo l'esecuzione di un sistema esperto che cerca di capire la specie cui appartiene
un animale.
16

Le risposte dell'utente sono in grassetto, l'output del sistema in corsivo.


Domanda, prego:
peter una tigre.
E' vero: peter ha il pelo?
si.
E' vero: peter mangia carne?
no.
E' vero: peter ha denti appuntiti?
si.
E' vero: peter ha artigli?
perch.
Per capire, tramite la regola 3, se peter un carnivoro
Per capire, tramite la regola 5, se peter una tigre
Questa era la tua domanda.
E' vero: peter ha artigli?
si.
E' vero: peter ha gli occhi frontali?
si.
E' vero: peter ha un colore fulvo?
si.
E' vero: peter ha strisce nere?
si.
17

(peter una tigre) vero


Vuoi vedere come l'ho dedotto?
si.
peter una tigre
stato dedotto tramite la regola 5 da
peter un carnivoro
stato dedotto tramite la regola 3 da
peter un mammifero
stato dedotto tramite la regola 1 da
peter ha il pelo
stato detto
e
peter ha denti appuntiti
stato detto
e
peter ha artigli
stato detto
e
peter ha occhi frontali
stato detto
peter ha un colore fulvo
stato detto
e
peter ha strisce nere
stato detto

18

UN SISTEMA ESPERTO
PER LA DIAGNOSI DI MALATTIE DA ITTERO
Ittero presente

si
Paziente giovane?
(1)

Ittero franco

Ittero Sclerale

Febbre?

Febbre?
no

Paziente giovane?

no
Stress o digiuno
nell'ultimo periodo?

no
si
Storia di abuso
di alcool?
si
Aumento di volume
del fegato?
si
Aumento di volume
della milza?
si
Cirrosi alcolica

19

Sindrome di Gibert

Paziente giovane?
(1)
si

no

Stanchezza(Astenia)?

Dolori ricorrenti a livello


del quadrante superiore
destro prima dell'ittero?

si
si
Disturbi dispeptici?

Dolore a livello
della coleciste?

si
si
Aumento di volume
del fegato?

Colecistite
(Colangite)

si
Epatite acuta virale

20

/* Regole di alto livello per la diagnosi */

diagnosi('Sindrome di Gibert') :- ittero_sclerale,


chiedi_se_non(ha(febbre)), stress_digiuno.
diagnosi('Epatite acuta virale') :- ittero_franco,
chiedi_se(ha(febbre)), chiedi_se(giovane),
chiedi_se(stanchezza), chiedi_se(dispepsia),
chiedi_se(aumento_fegato).
diagnosi('Colecistite') :- ittero_franco, chiedi_se(ha(febbre)),
chiedi_se_non(giovane), chiedi_se(dolori_ricorrenti),
chiedi_se(dolore_coleciste).
diagnosi('Cirrosi alcolica') :- ittero_franco,
chiedi_se_non(ha(febbre)), chiedi_se_non(giovane),
chiedi_se(alcool), chiedi_se(aumento_fegato),
chiedi_se(aumento_milza).
diagnosi('Il paziente non presenta nessuna delle malattie contemplate
dal sistema').

/* Regole intermedie per la diagnosi */

ittero_sclerale :- chiedi_se(occhi_gialli),
chiedi_se_non(colorito_giallo).

ittero_franco :- chiedi_se(occhi_gialli), chiedi_se(colorito_giallo).

stress_digiuno :- chiedi_se(stress).
stress_digiuno :- chiedi_se(digiuno).

eta_medio_avanzata :- chiedi_se_non(giovane).

21

/* Decodifica domande e relative spiegazioni */

cod_domanda(occhi_gialli,'Il paziente ha gli occhi giallastri').


spiega(occhi_gialli) :- write('Mi serve per verificare la presenza di
ittero'), nl.

cod_domanda(colorito_giallo,'Il paziente ha anche un colorito


giallastro').
spiega(colorito_giallo) :- write('Mi serve per distinguere l''ittero
sclerale da quello franco'), nl.

cod_domanda(stress,'Il paziente ha accusato stress in questo


periodo').
spiega(stress) :- write('La presenza di stress o digiuno fa
propendere per la Sindrome di Gibert'), nl.

cod_domanda(digiuno,'Il paziente ha digiunato in questo periodo').


spiega(digiuno) :- write('La presenza di stress o digiuno fa
propendere per la Sindrome di Gibert'), nl.

cod_domanda(giovane,'Il paziente e'' giovane').


spiega(giovane) :- write('Il fatto che il paziente sia giovane o di
eta'' medio-avanzata porta ad esaminare diagnosi
diverse'), nl.

cod_domanda(stanchezza,'Il paziente ha accusato astenia').


spiega(stanchezza) :- write('La presenza di stanchezza nel paziente
potrebbe essere indice di epatite acuta virale'), nl.

cod_domanda(dispepsia,'Il paziente ha avuto disturbi dispeptici').


spiega(dispepsia) :- write('La presenza di disturbi dispeptici
potrebbe essere indice di epatite acuta virale'), nl.
22

cod_domanda(aumento_fegato,'Si e'' riscontrato un aumento di volume


del fegato nel paziente').
spiega(aumento_fegato) :- write('In base alle risposte precedenti,
questa informazione potrebbe aiutare a distinguere
epatite e cirrosi dalle altre malattie'), nl.

cod_domanda(dolori_ricorrenti,'Prima dell''ittero il paziente


accusava dolori ricorrenti al quadrante superiore
destro').
spiega(dolori_ricorrenti) :- write('Ittero franco, febbre ed eta''
medio-avanzata fanno supporre una colecistite, che in
questo modo potrebbe essere confermata'), nl.

cod_domanda(dolore_coleciste,'Il paziente accusa dolore a livello


della coleciste').
spiega(dolore_coleciste) :- write('In base ai sintomi precedenti,
confermerebbe la presenza di colecistite'), nl.

cod_domanda(alcool,'E'' noto che il paziente ha abusato di alcool').


spiega(alcool) :- write('Sarebbe un indizio a favore della cirrosi'),
nl.

cod_domanda(aumento_milza,'Si e'' riscontrato un aumento di volume


della milza nel paziente').
spiega(aumento_milza) :- write('E'' un sintomo tipico della cirrosi,
insieme all''aumento di volume del fegato, nelle storie
di abuso di alcool'), nl.

cod_domanda(ha(X),X) :- write('Il paziente ha ').


spiega(ha(febbre)) :- write('Nota la presenza dell''ittero franco,
consente di prendere in considerazione alcune diagnosi
piuttosto che altre'), nl.
23

/* Motore inferenziale */

chiedi_se(Q) :- domanda(Q,A), risposta_positiva(Q,A).

risposta_positiva(Q,A) :- affermativa(A).
risposta_positiva(Qcode,A) :- not(negativa(A)), not(affermativa(A)),
write('Rispondere si o no.'), read(A2),
retract(gia_chiesto(Qcode,A)),
asserta(gia_chiesto(Qcode,A2)), affermativa(A2).

chiedi_se_non(Q) :- not(chiedi_se(Q)).

domanda(Qcode,A) :- gia_chiesto(Qcode,A).
domanda(Qcode,A) :- not(gia_chiesto(Qcode,A)), cod_domanda(Qcode,Q),
write(Q), write('? '), read(A2),
domanda2(Q,Qcode,A2,A).

domanda2(Q,Qcode,'spiega',A) :- spiega(Qcode), domanda(Qcode,A).


domanda2(Q,Qcode,A,A) :- not(A = 'spiega'),
asserta(gia_chiesto(Qcode,A)).

affermativa(si).
affermativa(s).
affermativa(giusto).
affermativa(ok).
affermativa(certo).

negativa(no).
negativa(n).
negativa(non).
negativa(mai).
negativa(impossibile).
24

UN SISTEMA ESPERTO
PER LA DIAGNOSI DEI GUASTI
DI UN DISPOSITIVO ELETTRICO
/* Top-level diagnosis rules */

diagnosis('Fuse blown') :- power_problem, askif(lights_out).


diagnosis('Fuse blown') :- power_problem, askif(hear(pop)).
diagnosis('Break in cord') :- power_problem, askif(cord_frayed).
diagnosis('Short in cord') :- diagnosis('Fuse blown'), askif(cord_frayed).
diagnosis('Device not turned on') :- power_problem, klutz_user, askif(has('an onoff switch or control')), askifnot(device_on).
diagnosis('Cord not in socket properly') :- power_problem, klutz_user,
askif(just_plugged), askifnot(in_socket).
diagnosis('Foreign matter caught on heating element') :- heating_element,
not(power_problem), askif(smell_smoke).
diagnosis('Appliance wet(emdry it out and try again') :- power_poblem, klutz_user,
askif(liquids).
diagnosis('Controls adjusted improperly') :- klutz_user, askif(has('knobs or
switches')).
diagnosis('Kick it, then try it again') :- mechanical_problem.
diagnosis('Throw it out and get a new one').

/* Definitions of intermediate predicates */

power_problem :- askif(device_dead).
power_problem :- askif(has('knobs or switches')), askifnot(knobs_do_something).
power_problem :- askif(smell_smoke), not(heating_element).

klutz_user :- askifnot(handyperson).
klutz_user :- askifnot(familiar_appliance).

mechanical_problem :- askif(hear('weird noise')), askif(has('moving parts')).

heating_element :- askif(heats).
heating_element :- askif(powerful).

25

/* Question decoding */

questioncode(device_dead,'Does the device refuse to do anything').


questioncode(knobs_do_something,'Does changing the switch positions or tuning the
knobs change anything').
questioncode(lights_out,'Do all the lights in the house seem to be off').
questioncode(cord_frayed,'Does the outer covering of the cord appear to be coming
apart').
questioncode(handyperson,'Are you good at fixing things').
questioncode(familiar_appliance,'Are you familiar with how this appliance works').
questioncode(device_on,'Is the ON/OFF switch set to ON').
questioncode(just_plugged,'Did you just plug the appliance in').
questioncode(in_socket,'Is the cord firmly plugged into the socket').
questioncode(smell_smoke,'Do you smell smoke').
questioncode(liquids,'Have any liquids spilled on the appliance just now').
questioncode(heats,'Does the appliance heat things').
questioncode(powerful,'Does the appliance require a lot of power').
questioncode(has(X),X) :- write('Does the appliance have ').
questioncode(hear(X),X) :- write('Did you hear a ').

/* Inferential engine */

askif(Q) :- ask(Q,A), positive_answer(Q,A).

positive_answer(Q,A) :- affirmative(A).
positive_answer(Qcode,A) :- not(negative(A)), not(affirmative(A)), write('Please
answer yes or no.'), read(A2), retract(asked(Qcode,A)),
asserta(asked(Qcode,A2)), affirmative(A2).

askifnot(Q) :- not(askif(Q)).

ask(Qcode,A) :- asked(Qcode,A).
ask(Qcode,A) :- not(asked(Qcode,A)), questioncode(Qcode,Q), write(Q), write('?'),
read(A2), ask2(Q,Qcode,A2,A).

ask2(Q,Qcode,'?',A) :- explain(Qcode), ask(Qcode,A).


ask2(Q,Qcode,A,A) :- not(A = '?'), asserta(asked(Qcode,A)).
26

affirmative(yes).
affirmative(y).
affirmative(ye).
affirmative(right).
affirmative(ok).
affirmative(uhhuh).

negative(no).
negative(n).
negative(not).
negative(never).
negative(impossible).
negative(haha).

27