• Non ci sono risultati.

VISUAL PROLOG Classi - Liste. Giovanni Torrero

N/A
N/A
Protected

Academic year: 2022

Condividi "VISUAL PROLOG Classi - Liste. Giovanni Torrero"

Copied!
81
0
0

Testo completo

(1)

Giovanni Torrero

(2)
(3)

2.1. Definizione 49

2.2. Backtracking 65

2.3. La classe list 69

Indice analitico 79

Bibliografia 81

3

(4)
(5)

Nella programmazione ad oggetti il concetto di oggetto svol- ge una parte molto importante, possiamo dire che un ogget- to è equivalente a un dato solo che il suo contenuto è più complesso. Un dato è costituito da un tipo di dato e da un suo valore, gli oggetti sono di tipo class mentre il suo valore viene stabilito al momento della costruzione dell’oggetto e può essere successivamente cambiato.

Il tipo class è un tipo un po’ particolare perché rappresen- ta qualche cosa che è un mini programma Prolog, quindi contiene sia dati che clausole.

Il tipo class essendo un mini programma deve essere suddi- viso in sezioni, l’IDE del Visual Prolog è molto intuitivo quindi è facile costruire un nuovo progetto e inserire in esso una nuova classe, nel conseguente albero del progetto si può notare la presenza di nuovi file

5

(6)

Di questi nuovi file noi dovremo gestirne essenzialmente il

primo e l’ultimo , se apriamo uno

di essi

vediamo come esso sia già diviso in sezioni: la sezione co- stantse la sezione clauses.

Se andiamo a consultare il menù Help di Visual Prolog

possiamo richiamare la:

(7)

Figura 1.1.1. Programma in Visual Prolog

Alle sezioni di cui sopra bisogna aggiungere la sezioneclau- ses ivi non riportata perché non è una sezione di dichiara- zioni ma si tratta del codice vero e proprio.

Siccome l’IDE del Visual Prolog è molto intuitivo e da vera- mente un grosso aiuto al programmatore non è necessario conoscere tutti i minimi dettagli delle istruzioni usate du- rante la stesura di un programma, è necessario conoscere solo i concetti fondamentali di questo tipo di programmazio- ne, i dettagli della sintassi e della gestione del programma li risolve l’IDE.

Dopo aver lanciato il Visual Prolog scegliere , successivamente riempire il form come indicato nella sot- tostante figura:

(8)

Comparirà il seguente albero del progetto

A questo punto dovete scegliere :

(9)

Fate doppio click su “New In ...” , si aprirà il seguente form:

(10)

Fatto quanto detto apparirà nella finestra dell’IDE l’immagi- ne del form appena creato assieme ad altre tre finestre

(11)

più controlli, la finestra Properties ci permette di conosce- re le proprietà dei controlli e delle finestre selezionate ed eventualmente modificarle, quindi è utilissima.

Trascinando i controlli si può riempire il forma come indi- cato nella figura di cui sopra, usando la finestra Properties modificare il loro aspetto come indicato nella figura di cui sotto

(12)

Come fare per fare apparire il form quando il programma viene lanciato? Andate nell’albero del progetto e scegliete apparirà il form sottostante nel quale dovete fare le scelte indicate

Chiudete il form, vi verrà chiesto di salvare e voi salvate, a questo punto ritornate sull’albero del progetto e sceglie- te comparirà il form sottostante nel quale, aprendo le linguette e utilizzando il testo destro del mouse, fate le scelte ivi indicate

(13)

Verrete spediti sul file con il cursore posizio- nato subito dopo la parte evidenziata che è quella che Visual Prolog ha automaticamente costruito.

(14)

è quella la parte di codice da modificare se volete che, quan-

do selezionate , appaia il form che avete costruito.

(15)

Dopo aver fatte le modifiche di cui sopra compilate con , quando il compilatore avrà fatto tutto il suo lavoro comparirà un messaggio di avvertimento

questo perché voi la variabile X dopo averla legata ad un certo valore con la clausolaX=dati::display(W)non l’ave- te più usata, non ha per voi nessun interesse, in questi ca- si è bene avvisare il compilatore di questa vostra esigenza mettendo un segno “_” davanti a X

(16)

Ricompilando il tutto vedrete che il compilatore non si la- menterà più.

Riepilogando: i nomi delle variabili iniziano tutti con lettere maiuscole, se un nome di una variabile è preceduto da “_”

significa che per il programmatore quella variabile non ha, in quel momento, nessun interesse e, soprattutto non ver- rà usata in seguito. Una variabile del genere serve solo a riempire un buco e viene detta variabile anonima , in realtà la variabile anonima è rappresentata dalla sola “_”, in effetti se noi cambiamo “_X” in “_”

non cambia nulla come si può vedere ricompilando e riese- guendo con .

Un simbolo il cui significato non è ancora noto è il seguente

“::”, nel frammento di codice da noi analizzato compare due volte

(17)

Se voi andate a vedere la classe dati vi accorgerete che contiene la clausoladisplay

la quale è dichiarata non inDati.proma in Dati.cl

(18)

Possiamo affermare che“::” viene usato per richiamare una clausola di una classe tramite il nome stesso della classe e non tramite un suo oggetto 1

Inoltre i nuovi predicati vanno sempre dichiarati, se vengono dichiarati nel file“...pro”sono visibili solo all’interno del file stesso, in pratica sono privati, se vengono dichiarati nel file

“...cl” sono visibili dappertutto cioè sono pubblici.

Molto interessante è il modo con cui viene dichiarato il pre- dicato display:

Il frammento di codice già visto prima

1Vedremo che per richiamare una clausola tramite il nome di un oggetto si usa il simbolo“:”.

(19)

L’oggetto Form viene costruito da new(Parent) nella clau- sola , è sempre new che costruisce gli og- getti . Bisogna ancora osservare che la variabile Form vi- ve solamente all’interno di questa clausola, tutte le variabi- li vivono solamente nelle clausole nelle quali sono definite, hanno visibilità limitata alla clausola, una seconda variabi- le Form di un’altra clausola non ha nulla a che vedere con quella di questa clausola.

É importante osservare l’uso di “=” fatto in questo frammen- to , il suo effetto è quello di far si che le due variabili, quella di destra e quella di sinistra siano legate allo stesso valo- re, in new(Parent) restituisce l’oggetto appena creato allora anche Form verrà collegata allo stes- so oggetto, allo stesso modo farà si che display(Parent) restituisca lo stesso oggetto.

Da ultimo rimane da sottolineare il frammento

nel quale è da rimarcare l’uso dei “:” infatti Form è un og- getto e non una classe e per richiamare le sue clausole usa i

“:”.

Se compilate ed eseguite il tutto vedrete che facendo click su File -> New

(20)

oppure su

comparirà il form prima costruito

(21)

Il form per ora è morto, non è in grado di fare nulla , è ab- bastanza ovvio che il suo scopo è quello di calcolare la po- tenza di un certo numero noti l’esponente e la base, per fa- re ciò useremo una apposita classe, anche se non sarebbe strettamente necessario.

Per produrre una nuova classe si va sull’albero del progetto e si sceglie la cartella indicata nella sottostante figura

poi mediante il tasto

si richiama il seguente form

(22)

infine premere e nell’albero del progetto compa- rirà la nuova cartellaPotPot . Rimanendo sull’albero del pro- getto con il tasto destro fate la scelta indicata nella sotto- stante figura

si aprirà il seguente form nel quale fate ciò che è indicato nella sottostante figura

infine premete , compilate e se andate nel packa- ge PotPot troverete tutti i file della classe appena creata.

I file che costituiscono la classe appena creata sono 5

(23)

ignoriamo per il momento gli ultimi due. Il file potenza.cl contiene le dichiarazioni dei predicati, relativi alla classe, vi- sibili in tutto il progetto. Dopo che avremo finito di scrivere tutta la classe questo file conterrà quanto segue:

1 /∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗

2 potenza . c l

3

∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ /

4 class potenza : potenza

5 open core

6 7 /∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗

8 LE DUE RIGHE SEGUENTI

9 SONO STATE AGGIUNTE MAUALMENTE

10

∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ /

11 constructors

12 new: ( r e a l Base , integer Esponente ) .

13 14 predicates

15 c l a s s I n f o : core : : c l a s s I n f o .

16

% @short Class information predicate .

17

% @detail This predicate represents information predicate of t h i s class .

18

% @end

19 20 end class potenza

le uniche due righe aggiunte sono quelle indicate nel lista- to precedente tutto il resto è costruito automaticamente da Visual Prolog.

Il secondo file è potenza.i che contiene l’interfaccia della classe, analizzeremo in seguito le interfacce per il momento diamo solo un’occhiata a questo file

(24)

1 /∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗

2 potenza . i

3

∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ /

4 5 i n t e r f a c e potenza

6 open core

7 8 /∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗

9 La sezione " predicates " non è stata

10 generata automaticamente ma aggiunta

11 i n seguito .

12

∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ /

13 predicates

14 setBase : ( r e a l Base ) .

15 setEsponente : (integer Esponente ) .

16 getPotenza : ( r e a l Potenza ) procedure ( o ) .

17 18 19 end i n t e r f a c e potenza

L’interfaccia è una proto-classe contiene solo dichiarazioni di predicati, domini, fatti, costanti ed altro e non implementa clausole. Una interfaccia non può produrre oggetti però può essere supportata da altre interfacce e può essere l’interfac- cia di una classe, nel nostro caso, come si può dedurre dal listato potenza.cl , l’intestazione della classe potenza è del tipo

e contiene l’indicazione della sua interfaccia. Il nome di una

(25)

Questo file, generato automaticamente, è stato modificato solo nelle quattro righe riguardanti la sezione predicates.

Queste quattro righe contengono i nomi dei predicati di do- minio pubblico usati dalla classe, queste dichiarazioni sono del seguente tipo

• il nome del predicato deve iniziare con una lettera minuscola;

• i parametri vengono individuati dal loro dominio, il nome è opzionale e viene comunque ignorato, se c’è deve iniziare con una lettera maiuscola, cioè deve essere una variabile;

• il tipo di predicato è opzionale e può essere:

(26)

determ: il predicato può avere successo oppure fallire ma sempre con un solo risultato,

procedure: il predicato ha sempre successo con un solo risultato,

multi: il predicato ha sempre successo con più soluzioni,

nondeterm: il predicato può avere successo oppure fallire con più soluzioni;

• la dichiarazione del tipo di parametri è opzionale, si tratta di una sequenza ordinato di “o” e “i”, “o”

vuol dire che il parametro è un parametro di out- put e quindi non deve essere legato a nessun valo- re, mentre “i” vuol dire parametro di input e quindi deve essere legato.

Da ultimo prendiamo in esame il file potenza.pro , ecco il listato definitivo del file

(27)

6 open core

7 8 constants

9 className = " PotPot / potenza" .

10 classVersion = " " .

11 12 /∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗

13 i n i z i o d e l l a parte non generata

14 automaticamente

15

∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ /

16 17 f a c t s

18 base : r e a l .

19 esponente : integer .

20 21 clauses

22 new( Base , Esponente ) :−

23 base := Base ,

24 esponente := Esponente .

25 26 clauses

27 c l a s s I n f o ( className , classVersion ) .

28 29 setBase (B) :− base := B .

30 setEsponente (E) :− esponente := E .

31 32 predicates

33 34 calcola : ( r e a l Base , integer Esponente , real

Potenza ) procedure ( i , i , o ) .

35 36 clauses

37 calcola (B, 1 , P ) :− P=B , ! .

38 calcola (B, E , P ) :− calcola (B, E−1,P1) ,

39 P=P1∗B .

(28)

Cominciamo con l’analizzare la sezione “constants”, come dice la parola stessa sono delle costanti alle quali viene da- to il nome, nel programma usare className oppure usare la stringa “PotPot/potenza” è la stessa cosa, il contenuto di una costante è immutabile durante tutto il programma ed il suo nome deve iniziare con una lettera minuscola . La defi- nizione di una costante può essere fatta in uno dei seguenti modi:

nomeDellaCostante = ValoreDellaCostante.

oppure

nomeDellaCostante:tipoDellaCostante = ValoreDellaCostan- te.

Il tipoDellaCostante si può omettere nel caso in cui esso sia:

• un tipo numerico, ad esempio: integer, real etc;

• un tipo stringa;

• un tipo carattere;

• un tipo binario.

Nel nostro caso abbiamo:

constants

className = "PotPot/potenza".

classVersion = "".

Il tipo non è stato messo perché si tratta sempre del tipo stringa e quindi si può omettere. Se noi aggiungiamo il tipo

tutto continua a funzionare come prima.

Questa sezione è prodotta automaticamente da Visual Pro- log mentre la parte successiva bisogna scriverla manual- mente.

Cominciamo con il descrivere la sezione facts, i fatti sono delle clausole di Horn senza la coda, come è noto le clausole di Horn hanno una struttura di questo tipo:

Testa :- Coda

nei fatti c’è solo la testa.

(29)

nel database interno tramite assert, a loro vengono asse- gnati dei valori, appartenenti a un dominio, indicato nella dichiarazione, tramite l’operatore :=.

I fatti-funtore vengono inseriti nel database interno, sono molto importanti ma adesso non vogliamo trattarli.

I fatti devono essere dichiarati, ciò può avvenire solo nel file ...pro e sono visibili solo in questo contesto. La dichiara- zione è di questo tipo:

si può anche assegnare un valore tramite l’operatore :=

e ricompilando si vede che tutto funzione come prima, in questo caso i valori iniziali sono inutili.

Una volta dichiarati i fatti possono essere usati nelle clausole e si può cambiare il loro valore tramite := come ad esempio nel seguente frammento di codice

(30)

Le clausole di cui sopra non hanno bisogno di commenti, i re- lativi predicati sono stati dichiarati in potenza.i , l’interfaccia della classe, e quindi sono visibili in tutto il progetto. Forse

l’unica cosa da aggiungere e che il predicatonew(Base,Esponente) è il costruttore della classe potenza, è cioè il predicato che

bisogna richiamare quando si vuole costruire un oggetto di questa classe.

Il predicato calcola viene definito in questo file e non nell’in- terfaccia, questo significa che potremo usarlo solo in questo file e non altrove.

Molto interessante è il sistema formato dalle clausolecalcola perché si tratta di un sistema di clausole ricorsive. Un siste- ma di clausole ricorsive é di solito formato da una clausola terminale e da una clausola che ha nella sua coda lo stesso predicato che forma la sua testa

(31)

Il processo ricorsivo viene innescato dalla clausolagetPoten- za

questa clausola lancia il goal con i due parametri di ingresso legati e quello di uscita non legato. Supponiamo che base valga 2 e esponentevalga 3 allora viene lanciato il goal cal- cola(2,3,P), la figura seguente illustra come viene eseguito il processo ricorsivo

(32)

Figura 1.1.2. Esecuzione del processo ricorsivo

Alla fine la variabilePviene legata a 8 e rappresenta il valore di uscita della funzione getPotenza, questa funzione verrà lanciata quando si fa click sul pulsanteCalcoladel formDati, quindi prendiamo in esame la gestione di tale form.

Richiamiamo il file

(33)

Dopo aver selezionato il pulsante Calcola, nella finestra Pro- perties eseguire la selezione indicata in figura

successivamente fate doppio click sulla scelta appena fatta e verrete proiettati sulla finestra dove è sta-

to costruito lo scheletro del predicatoonCalcolaPushButtonClick : button::clickResponder. che voi completerete come

indicato nella sottostante figura.

(34)

Analizziamo le clausole aggiunte

La prima di queste clausole prende il contenuto della casella di testo edit_ctl, che è una stringa, lo trasforma in un real e la variabileBaseviene unificata a questo numero reale.

Una cosa simile fa la seconda clausola, osservare l’uso della funzionetoterm otoTerm , è la stessa cosa, che prende una stringa e la trasforma in un numero2.

2Come toTerm distingua i numeri reali da quelli interi è un mistero.

(35)

unificando la variabilePal risultato del calcolo.

La variabile P , appena unificata, viene trasformata in una stringa da toString(P) 5 dopodiché l’oggetto edit2_ctl richia- ma il suo predicato setText aggiornando così il campo di testo.

1.2. Salvare il lavoro

Dopo aver imparato a maneggiare un po’ le classi e gli og- getti c’è una cosa che ancora mi angustia, salvare il lavoro fatto sul disco. Questa parte, anche se breve, è molto impor- tante perché sono riuscito a trovare una finestra di dialogo che riproduce la classica finestra grazie alla quale si sceglie il percorso .

Innanzitutto bisogna costruire un nuovo progetto

3Osservare l’uso dei“::” perché è la classepotenza che richiama il suo costruttore.

4Un riferimento è qualche cosa di simile a un puntatore.

5toString trasforma qualsiasi cosa in una stringa.

(36)

Create un nuovo package usando

e

(37)

Create un nuovo form sempre usando New

(38)

Popolate il nuovo form

(39)
(40)

Attivate il menu File->New e quindi anche il relativo tasto della toolbar , per fare ciò nell’albero del progetto fate

Compare

Nell’albero del progetto selezionare

(41)

Appare

(42)

Successivamente fate

(43)

e vi troverete su

(44)

nel quale farete le modifiche indicate. Osservate la crea- zione di un nuovo oggetto di tipo “contenitore”, il cui riferi- mento viene assegnato alla variabileF, tramite“::new”, suc- cessivamente viene richiamato il metodo “F:show()” che fa apparire il form creato.

Occupiamoci di dare funzionalità ai due testi “Salva” e “Apri”

del form contenitore prima creato. Nell’albero del progetto selezionate

Doppio click ed appare

Nella corrispondente finestra delle proprietà selezionate e riempite come indicato nella sottostante figura

(45)

Doppio click suonSaveClick e verrete catapultati su

La testa della clausola evidenziata: ,

mi è piuttosto strana, ma questa parte è generata automati- camente quindi non facciamoci troppi problemi e passiamo oltre.

Subito oltre troviamo edit_ctlè un oggetto della classe editControl che a sua volta implementa l’inter- faccia editControl la quale contiene tutta una serie di predi- cati, la creazione di questo oggetto avviene nella parte di co-

dice generato automaticamente nella clausola successivamente vengono impostati vari parametri, ma noi di tutto questo

non ce ne dobbiamo preoccupare perché sta tutto nel codice generato automaticamente. Ritornando alla nostra clausola

(46)

iniziale essa lega la variabile Txt al contenuto del controllo edit_ctl.

La successiva clausola è molto importante:

FName= vpiCommonDialogs::getFileName("*.*", ["Text", "*.txt"],

"Save", [], ".", _X),

Esiste la classe vpiCommonDialogs , ecco cosa c’è scritto a proposito di questa classe sulla guida di Visual Prolog:

Class vpiCommonDialogs Package: vpi

Class vpiCommonDialogs contains predicates for creating common dialogs.

Tra i vari predicati della classe troviamo questo:

non perdiamo tempo per illustrare le varie parti si può trova- re tutto questo nell’Help di Visual Prolog in Sommario->vpi-

>vpiCommonDialogs. L’effetto di questa clausola è quello di far apparire una bellissima finestra di dialogo del tutto uguale a quella che normalmente si usano in Windows per memorizzare i file.

Successivamente troviamo il predicato predefinito“!”, detto

“cut”, come è noto detto predicato rende unica la soluzio- ne della clausola iniziale perché congela tutte le unificazio- ni fatte e non permette più il backtraking della parte della clausola precedente il cut, tutto questo perché onSaveClick deve essere di tipo determ, cioè deve avere una ed una so- la soluzione. La successiva clausola è

che è la clausola che effettivamente scrive il contenuto della variabile Txtsul file a cui è legataFName.

La successiva clausola serve

solo a fare in modo che la clausola onSaveClick abbia sem- pre successo.

(47)
(48)
(49)

Le liste esistevano già nel vecchio Turbo Prolog quindi comin- ciamo con il vedere di che cosa si tratta usando qualche cosa di molto simile al vecchio Turbo Prolog: il progetto “pie”.

Andate su Project->Open

andate a cercare in un percorso simile a quello sotto indicato

aprite il progetto pieed eseguite

49

(50)

verrete catapultati in un nuovo mondo il cui aspetto è il se- guente 1

1Una volta eseguito si forma il filepie.exenel percorsoC:\Documents and Settings\...\Documenti\Visual Prolog Examples\pie\exe

lanciando il quale si arriva allo stesso risultato.

(51)

Naturalmente andiamo subito su New

e ci troveremo di fronte a qualche cosa del genere

(52)

Scriviamo alcune clausole

(53)

Salviamo il tutto

(54)

Premiamo il taso“Reconsult”

Nella finestra “Dialog”compare il relativo comando

(55)

Sempre nella finestra “Dialog”si può scrivere un goal come questo

(56)

Premendo “Return”si ottiene

Innanzitutto è da notare la mancanza di dichiarazioni dei predicati usati, infattipieè un prolog interpretato, come altri prolog ad esempioSWIProlog, e non ha bisogno di tutti i con- trolli che invece deve fare Visual Prolog. Con pie si scrivono direttamente le clausole che poi vengono consultate trami- te un goal scritto nella finestra dialog, questo goal è una clausola che si cercherà di unificare con le clausole scritte nell’altra finestra, l’unica operazione che bisogna fare prima di lanciare il goal e quella di premere il tastoReconsult.

(57)

Una lista è un costrutto di questo tipo:

[a, b, c, d, e, f, g]

dove a, b, c, d, e, f, g possono essere qualunque tipo di dati:

interi, numeri reali, stringhe, oggetti, altre liste.

Le liste si dividono in due parti: la testa e la coda, l’ope- ratore che effettua questa suddivisione è “|” usato nel goal della figura precedente , basta osservare il risultato per ve- dere come funziona. L’operatore “|” lo si può usare in modo abbastanza disinvolto, ecco un nuovo goal che ci illustra un altro uso di detto operatore:

(58)

Vediamo ora di fare qualche cosa di leggermente più com- plesso, data una lista vogliamo contare quante volte un ele- mento è presente nella lista

Dopo aver salvato e premuto il tasto nella finestra Dialog lanciamo il goalcerca(a).

Per vedere come si comporta questo programma usiamo la direttiva trace nella finestra Dialog

(59)

True

1 Solution cerca(a).

(1) Trace: >> CALL: cerca(a)

(2) Trace: >> CALL: esiste([a,b,c,b,a,f,g,h,a,l],a,N$81) (3) Trace: >> CALL: esiste([b,c,b,a,f,g,h,a,l],a,NV$82) (4) Trace: >> CALL: esiste([c,b,a,f,g,h,a,l],a,NV$83) (5) Trace: >> CALL: esiste([b,a,f,g,h,a,l],a,NV$84) (6) Trace: >> CALL: esiste([a,f,g,h,a,l],a,NV$85) (7) Trace: >> CALL: esiste([f,g,h,a,l],a,NV$86) (8) Trace: >> CALL: esiste([g,h,a,l],a,NV$87) (9) Trace: >> CALL: esiste([h,a,l],a,NV$88) (10) Trace: >> CALL: esiste([a,l],a,NV$89) (11) Trace: >> CALL: esiste([l],a,NV$90) (12) Trace: >> CALL: esiste([],a,NV$91) (13) Trace: >> CALL: NV$91 = 0

(14) Trace: >> RETURN: 0 = 0

(15) Trace: >> RETURN: esiste([],a,0) (16) Trace: >> CALL: uguali(l,a,N1$92,0) (17) Trace: >> CALL: a = l

(18) Trace: >> FAIL: a = l (19) Trace: >> CALL: N1$92 = 0 (20) Trace: >> RETURN: 0 = 0

(21) Trace: >> RETURN: uguali(l,a,0,0) (22) Trace: >> CALL: NV$90 = 0

(23) Trace: >> RETURN: 0 = 0

(24) Trace: >> RETURN: esiste([l],a,0) (25) Trace: >> CALL: uguali(a,a,N1$93,0) (26) Trace: >> CALL: a = a

(27) Trace: >> RETURN: a = a (28) Trace: >> CALL: N1$93 = 1 (29) Trace: >> RETURN: 1 = 1

(30) Trace: >> RETURN: uguali(a,a,1,0) (31) Trace: >> CALL: NV$89 = 1

(60)

(32) Trace: >> RETURN: 1 = 1

(33) Trace: >> RETURN: esiste([a,l],a,1) (34) Trace: >> CALL: uguali(h,a,N1$94,1) (35) Trace: >> CALL: a = h

(36) Trace: >> FAIL: a = h (37) Trace: >> CALL: N1$94 = 1 (38) Trace: >> RETURN: 1 = 1

(39) Trace: >> RETURN: uguali(h,a,1,1) (40) Trace: >> CALL: NV$88 = 1

(41) Trace: >> RETURN: 1 = 1

(42) Trace: >> RETURN: esiste([h,a,l],a,1) (43) Trace: >> CALL: uguali(g,a,N1$95,1) (44) Trace: >> CALL: a = g

(45) Trace: >> FAIL: a = g (46) Trace: >> CALL: N1$95 = 1 (47) Trace: >> RETURN: 1 = 1

(48) Trace: >> RETURN: uguali(g,a,1,1) (49) Trace: >> CALL: NV$87 = 1

(50) Trace: >> RETURN: 1 = 1

(51) Trace: >> RETURN: esiste([g,h,a,l],a,1) (52) Trace: >> CALL: uguali(f,a,N1$96,1) (53) Trace: >> CALL: a = f

(54) Trace: >> FAIL: a = f (55) Trace: >> CALL: N1$96 = 1 (56) Trace: >> RETURN: 1 = 1

(57) Trace: >> RETURN: uguali(f,a,1,1) (58) Trace: >> CALL: NV$86 = 1

(59) Trace: >> RETURN: 1 = 1

(60) Trace: >> RETURN: esiste([f,g,h,a,l],a,1) (61) Trace: >> CALL: uguali(a,a,N1$97,1)

(62) Trace: >> CALL: a = a (63) Trace: >> RETURN: a = a (64) Trace: >> CALL: N1$97 = 2 (65) Trace: >> RETURN: 2 = 2

(66) Trace: >> RETURN: uguali(a,a,2,1) (67) Trace: >> CALL: NV$85 = 2

(68) Trace: >> RETURN: 2 = 2

(69) Trace: >> RETURN: esiste([a,f,g,h,a,l],a,2) (70) Trace: >> CALL: uguali(b,a,N1$98,2)

(71) Trace: >> CALL: a = b (72) Trace: >> FAIL: a = b (73) Trace: >> CALL: N1$98 = 2

(61)

(80) Trace: >> CALL: a = c (81) Trace: >> FAIL: a = c (82) Trace: >> CALL: N1$99 = 2 (83) Trace: >> RETURN: 2 = 2

(84) Trace: >> RETURN: uguali(c,a,2,2) (85) Trace: >> CALL: NV$83 = 2

(86) Trace: >> RETURN: 2 = 2

(87) Trace: >> RETURN: esiste([c,b,a,f,g,h,a,l],a,2) (88) Trace: >> CALL: uguali(b,a,N1$100,2)

(89) Trace: >> CALL: a = b (90) Trace: >> FAIL: a = b

(91) Trace: >> CALL: N1$100 = 2 (92) Trace: >> RETURN: 2 = 2

(93) Trace: >> RETURN: uguali(b,a,2,2) (94) Trace: >> CALL: NV$82 = 2

(95) Trace: >> RETURN: 2 = 2

(96) Trace: >> RETURN: esiste([b,c,b,a,f,g,h,a,l],a,2) (97) Trace: >> CALL: uguali(a,a,N1$101,2)

(98) Trace: >> CALL: a = a (99) Trace: >> RETURN: a = a (100) Trace: >> CALL: N1$101 = 3 (101) Trace: >> RETURN: 3 = 3

(102) Trace: >> RETURN: uguali(a,a,3,2) (103) Trace: >> CALL: N$81 = 3

(104) Trace: >> RETURN: 3 = 3

(105) Trace: >> RETURN: esiste([a,b,c,b,a,f,g,h,a,l],a,3) (106) Trace: >> CALL: nl()

(107) Trace: >> RETURN: nl()

(108) Trace: >> CALL: write(a, compare ,3, volte) (109) a compare 3 volteTrace: >> RETURN: write(a,

compare ,3, volte) (110) Trace: >> CALL: nl() (111) Trace: >> RETURN: nl() (112) Trace: >> RETURN: cerca(a) (113) True

(62)

1 Solution

Seguendo quanto prodotto dalla direttiva trace ci si può ren- dere conto del comportamento del Prolog resta comunque una certa difficoltà a seguire la logica dei programmi Pro- log. Lo schema seguente dovrebbe aiutare a chiarire questa logica:

Figura 2.1.1. Grafico del funzionamento del programma

(63)

senta l’attività che esso innesca, questo triangolo è bene in- dividuato dalle due rette parallele all’asse y che passano ri- spettivamente per il CALL e il RETURN (o FAIL) del sotto-goal considerato.

In questo schema ci sono alcune cose che sfuggono:

• il meccanismo ricorsivo non viene evidenziato;

• i predicati non compaiono direttamente se non nella didascalia soprastante;

• i parametri dei predicati sono ignorati se non nella didascalia soprastante;

• il modo con cui vengono legate le variabili non ap- pare per nulla.

Uno schema un po’ più elaborato che risolve parte dei pro- blemi sopra elencati è il seguente:

(64)

Figura 2.1.2. Grafico dei goal

Lo schema precedente è stato creato partendo dai goal e sotto goal che vengono via via lanciati, ogni goal ha una sua vita che si conclude con RETURN se ha avuto successo op- pure con FAIL se fallisce. Durante la sua vita un goal è per alcuni istanti attivo mentre per il rimanente periodo di tem- po rimane inattivo ( assonnato ). Nello schema ogni goal è individuato da un pallino blu , che indica l’istante della sua nascita, seguito da una riga che può essere: rossa , negli istanti in cui il goal è attivo, grigia , negli istanti in cui il goal è inattivo, questa riga termina con FAIL oppure RETURN . La prima cosa che si può osservare è che in ogni istante è attivo un solo goal, un goal può essere attivo a tratti perché spesso il corpo di una clausola è una congiunzione di goal, dallo schema inoltre si capisce abbastanza bene come vengono legate le variabili.

(65)

Questa cosa del backtracking non mi è del tutto chiara è meglio soffermarsi un momento su questo concetto.

2.2. Backtracking

Riprendiamo il programma precedente con le seguenti mo- difiche

Proviamo a vedere che cosa succede con la direttiva trace

Reconsulted from: C:\Documents and Settings\papi\Documenti\Visual Pro- log Examples\pie\exe\FILE2.PRO

trace.

True

1 Solution

(1) cerca(a).

(2) Trace: >> CALL: cerca(a)

(3) Trace: >> CALL: esiste([a,b,c,b,a,f,g,h,a,l],a,N$0) (4) Trace: >> CALL: esiste([b,c,b,a,f,g,h,a,l],a,NV$1) (5) Trace: >> CALL: esiste([c,b,a,f,g,h,a,l],a,NV$2)

(66)

(6) Trace: >> CALL: esiste([b,a,f,g,h,a,l],a,NV$3) (7) Trace: >> CALL: esiste([a,f,g,h,a,l],a,NV$4) (8) Trace: >> CALL: esiste([f,g,h,a,l],a,NV$5) (9) Trace: >> CALL: esiste([g,h,a,l],a,NV$6) (10) Trace: >> CALL: esiste([h,a,l],a,NV$7) (11) Trace: >> CALL: esiste([a,l],a,NV$8) (12) Trace: >> CALL: esiste([l],a,NV$9) (13) Trace: >> CALL: esiste([],a,NV$10) (14) Trace: >> CALL: NV$10 = 0

(15) Trace: >> RETURN: 0 = 0

(16) Trace: >> RETURN: esiste([],a,0) (17) Trace: >> CALL: uguali(l,a,N1$11,0) (18) Trace: >> CALL: N1$11 = 1

(19) Trace: >> RETURN: 1 = 1 (20) Trace: >> CALL: a = l (21) Trace: >> FAIL: a = l (22) Trace: >> REDO: 1 = 1 (23) Trace: >> FAIL: 1 = 1 (24) Trace: >> CALL: N1$11 = 0

'

&

$

%

.

Nelle tre righe precedenti è ben visibile come funziona il backtracking, la variabile N1$11 , che era stata legata al va- lore 1, viene slegata, si ritorna al goal immediatamente pre- cedenti : CALL: uguali(l,a,N1$11,0), cercando di soddi- sfarlo con la clausola immediatamente successiva a quella usata prima.

.

(25) Trace: >> RETURN: 0 = 0

(26) Trace: >> RETURN: uguali(l,a,0,0) (27) Trace: >> CALL: NV$9 = 0

(28) Trace: >> RETURN: 0 = 0

(29) Trace: >> RETURN: esiste([l],a,0) (30) Trace: >> CALL: uguali(a,a,N1$12,0) (31) Trace: >> CALL: N1$12 = 1

(32) Trace: >> RETURN: 1 = 1 (33) Trace: >> CALL: a = a (34) Trace: >> RETURN: a = a

(35) Trace: >> RETURN: uguali(a,a,1,0) (36) Trace: >> CALL: NV$8 = 1

(37) Trace: >> RETURN: 1 = 1

(38) Trace: >> RETURN: esiste([a,l],a,1) (39) Trace: >> CALL: uguali(h,a,N1$13,1) (40) Trace: >> CALL: N1$13 = 2

(67)

(47) Trace: >> RETURN: 1 = 1

(48) Trace: >> RETURN: uguali(h,a,1,1) (49) Trace: >> CALL: NV$7 = 1

(50) Trace: >> RETURN: 1 = 1

(51) Trace: >> RETURN: esiste([h,a,l],a,1) (52) Trace: >> CALL: uguali(g,a,N1$14,1) (53) Trace: >> CALL: N1$14 = 2

(54) Trace: >> RETURN: 2 = 2 (55) Trace: >> CALL: a = g (56) Trace: >> FAIL: a = g (57) Trace: >> REDO: 2 = 2 (58) Trace: >> FAIL: 2 = 2 (59) Trace: >> CALL: N1$14 = 1 (60) Trace: >> RETURN: 1 = 1

(61) Trace: >> RETURN: uguali(g,a,1,1) (62) Trace: >> CALL: NV$6 = 1

(63) Trace: >> RETURN: 1 = 1

(64) Trace: >> RETURN: esiste([g,h,a,l],a,1) (65) Trace: >> CALL: uguali(f,a,N1$15,1) (66) Trace: >> CALL: N1$15 = 2

(67) Trace: >> RETURN: 2 = 2 (68) Trace: >> CALL: a = f (69) Trace: >> FAIL: a = f (70) Trace: >> REDO: 2 = 2 (71) Trace: >> FAIL: 2 = 2 (72) Trace: >> CALL: N1$15 = 1 (73) Trace: >> RETURN: 1 = 1

(74) Trace: >> RETURN: uguali(f,a,1,1) (75) Trace: >> CALL: NV$5 = 1

(76) Trace: >> RETURN: 1 = 1

(77) Trace: >> RETURN: esiste([f,g,h,a,l],a,1) (78) Trace: >> CALL: uguali(a,a,N1$16,1)

(79) Trace: >> CALL: N1$16 = 2 (80) Trace: >> RETURN: 2 = 2 (81) Trace: >> CALL: a = a (82) Trace: >> RETURN: a = a

(83) Trace: >> RETURN: uguali(a,a,2,1) (84) Trace: >> CALL: NV$4 = 2

(85) Trace: >> RETURN: 2 = 2

(68)

(86) Trace: >> RETURN: esiste([a,f,g,h,a,l],a,2) (87) Trace: >> CALL: uguali(b,a,N1$17,2)

(88) Trace: >> CALL: N1$17 = 3 (89) Trace: >> RETURN: 3 = 3 (90) Trace: >> CALL: a = b (91) Trace: >> FAIL: a = b (92) Trace: >> REDO: 3 = 3 (93) Trace: >> FAIL: 3 = 3 (94) Trace: >> CALL: N1$17 = 2 (95) Trace: >> RETURN: 2 = 2

(96) Trace: >> RETURN: uguali(b,a,2,2) (97) Trace: >> CALL: NV$3 = 2

(98) Trace: >> RETURN: 2 = 2

(99) Trace: >> RETURN: esiste([b,a,f,g,h,a,l],a,2) (100) Trace: >> CALL: uguali(c,a,N1$18,2)

(101) Trace: >> CALL: N1$18 = 3 (102) Trace: >> RETURN: 3 = 3 (103) Trace: >> CALL: a = c (104) Trace: >> FAIL: a = c (105) Trace: >> REDO: 3 = 3 (106) Trace: >> FAIL: 3 = 3 (107) Trace: >> CALL: N1$18 = 2 (108) Trace: >> RETURN: 2 = 2

(109) Trace: >> RETURN: uguali(c,a,2,2) (110) Trace: >> CALL: NV$2 = 2

(111) Trace: >> RETURN: 2 = 2

(112) Trace: >> RETURN: esiste([c,b,a,f,g,h,a,l],a,2) (113) Trace: >> CALL: uguali(b,a,N1$19,2)

(114) Trace: >> CALL: N1$19 = 3 (115) Trace: >> RETURN: 3 = 3 (116) Trace: >> CALL: a = b (117) Trace: >> FAIL: a = b (118) Trace: >> REDO: 3 = 3 (119) Trace: >> FAIL: 3 = 3 (120) Trace: >> CALL: N1$19 = 2 (121) Trace: >> RETURN: 2 = 2

(122) Trace: >> RETURN: uguali(b,a,2,2) (123) Trace: >> CALL: NV$1 = 2

(124) Trace: >> RETURN: 2 = 2

(125) Trace: >> RETURN: esiste([b,c,b,a,f,g,h,a,l],a,2) (126) Trace: >> CALL: uguali(a,a,N1$20,2)

(127) Trace: >> CALL: N1$20 = 3 (128) Trace: >> RETURN: 3 = 3 (129) Trace: >> CALL: a = a (130) Trace: >> RETURN: a = a

(69)

(137) Trace: >> CALL: write(a, compare ,3, volte)

(138) a compare 3 volteTrace: >> RETURN: write(a, compare ,3, volte)

(139) Trace: >> CALL: nl() (140) Trace: >> RETURN: nl() (141) Trace: >> RETURN: cerca(a) (142) True

1 Solution

2.3. La classe list

Ritorniamo ad usare il Visual Prolog ed osserviamo che a proposito di liste esiste la classe list.

Ecco che cosa ho trovato nell’Help di Visual Prolog a propo- sito di questa classe:

Overview Package

SUMMARY: Domains Predicates DETAIL: Domains Predicates Class list

Package: list

The list class contains predicates to work on prolog lists.

Description

The predicates are declared using polymorphic list type creation, there the predicates can operate on any prolog lists.

Domain Summary filterPredicate

Deprecated use core::predicate_dt instead

Predicate Summary .

(70)

append: : (Elem* Front, Elem* Tail) -> Elem* List.

List is the result of appending Tail to Front.

append: : (Elem* Front1, Elem* Front2, Elem* Tail) -> Elem*

List.

List is the result of append(Front1, append(Front2, Tail)).

append: : (Elem* Front1, Elem* Front2, Elem* Front3, Elem*

Tail) -> Elem* List.

List is the result of append(Front1, append(Front2, ap- pend(Front3, Tail))).

append: : (Elem* Front1, Elem* Front2, Elem* Front3, Elem*

Front4, Elem* Tail) -> Elem* List.

List is the result of append(Front1, append(Front2, ap- pend(Front3, append(Front4, Tail)))).

appendList: : (Elem** ListList) -> Elem* List.

List is the result of appending all the lists in ListList.

classInfo: : classInfo.

Class information predicate.

decompose: : (Elem* List, function Separator) -> tuple*.

Decompose input list in some lists by Separator.

difference: : (Elem* List1, Elem* List2) -> Elem* List1ExceptList2.

differenceBy: : (comparator Comparator, Elem* List1, Elem2*

List2) -> Elem* List1ExceptList2.

differenceEq: : (predicate_dt Eq, Elem* List1, Elem2* List2) -> Elem* List1ExceptList2.

List1ExceptList2 contains the elements from List1 which are not in List2.

drop: : (positive Count, Elem* List) -> Elem* LastPart.

Drops the first Count elements from list List, and returns the remaining last elements as LastPart.

exists: : (Elem* List, predicate_dt Test) determ.

Succeeds if one of the members of List satisfies the Test.

filter: : (Elem* List, predicate_dt PositiveFilter) -> Elem*

FilteredPositiveList.

Extracts all items from List which fulfills the Filter.

(71)

OutElem.

Fold list over function

forAll: : (Elem* List, predicate Predicate).

Invoke Predicate for all list elements

getMember_nd: : (Elem* List) -> Elem Value nondeterm.

Returns the members Value of the list List.

getTupleMember_nd: : (tuple List) -> tuple Value nonde- term.

Tuple version of getMember_nd where two lists.

intersection: : (Elem* ListA, Elem* ListB) -> Elem* Inter- sectionAB.

intersectionBy: : (comparator Comparator, Elem* ListA, Elem* ListB) -> Elem* IntersectionAB.

intersectionEq: : (predicate_dt Eq, Elem* ListA, Elem* ListB) -> Elem* IntersectionAB.

Returns intersection of ListA and ListB.

isMember: : (Elem Value, Elem* List) determ.

isMemberBy: : (comparator Comparator, Test Value, Elem*

List) determ.

isMemberEq: : (predicate_dt Eq, Test Value, Elem* List) determ.

Succeds if Value is member of List.

length: : (Elem* List) -> positive Length.

Returns the length of the list List.

map: : (Elem* List, function Function) -> OutElem* NewList.

Convert list to another list

maximum: : (Elem* List) -> Elem Item.

maximumBy: : (comparator Comparator, Elem* List) ->

Elem Item.

Return maximum Item of List.

(72)

memberIndex_nd: : (Elem Value [out], positive Index [out], Elem* List) nondeterm.

Returns the members Value of the list List and their Index.

minimum: : (Elem* List) -> Elem Item.

minimumBy: : (comparator Comparator, Elem* List) ->

Elem Item.

Return minimum Item of List.

nDuplicates: : (Elem, positive N) -> Elem* NList.

Create list of N duplicates

nth: : (positive Index, Elem* List) -> Elem Item.

Return Item of List at position Index. Index is zero based.

remove: : (Elem* List, Elem Value) -> Elem* Rest.

removeAll: : (Elem* List, Elem Value) -> Elem* Rest.

removeAllBy: : (comparator Comparator, Elem* List, Elem2 Value) -> Elem* Rest.

removeAllEq: : (predicate_dt Eq, Elem* List, Elem2 Value) -> Elem* Rest.

Remove the all occurences of Value from List.

removeBy: : (comparator Comparator, Elem* List, Elem2 Value) -> Elem* Rest.

removeConsecutiveDuplicates: : (Elem* List) -> Elem*

Rest.

removeConsecutiveDuplicatesBy: : (core::comparator Com- parator, Elem* List) -> Elem* Rest.

removeConsecutiveDuplicatesEq: : (predicate_dt Eq, Elem*

List) -> Elem* Rest.

Remove the all consecutive duplicates from List (mainly for sorted list). Last occurences are retained. Complexity is O(N).

removeDuplicates: : (Elem* List) -> Elem* Rest.

removeDuplicatesBy: : (comparator Comparator, Elem*

List) -> Elem* Rest.

Remove the all duplicates from List. First occurences are retained. Complexity is O(N ln N)

removeDuplicatesEq: : (predicate_dt Eq, Elem* List) ->

Elem* Rest.

Remove the all duplicates from List. Last occurences are

(73)

reverse: : (Elem* List) -> Elem* Reverse.

Reverse is the reverse of List.

setNth: : (positive Index, Elem* List, Elem Item, Elem*

NewList [out]).

Returns the NewList with the Index’th element changed to Item. Index is zero based.

sort: : (Elem* List) -> Elem* Sorted.

sort: : (Elem* List, sortOrder Order) -> Elem* Sorted.

Sorted is the sorted version of List.

sortBy: : (comparator Comparator, Elem* List) -> Elem*

Sorted.

sortBy: : (comparator Comparator, Elem* List, sortOrder Order) -> Elem* Sorted.

Sorted is the sorted version of List.

split: : (positive Index, Elem* List, Elem* LeftList [out], Elem*

RightList [out]).

Splits the list List in two lists in a place of element of index Index. Index is zero based.

take: : (positive Count, Elem* List) -> Elem* FirstPart.

Takes the first Count elements from list List, and returns them as FirstPart.

tryGetIndex: : (Elem Item, Elem* List) -> positive Index determ.

tryGetIndexBy: : (comparator Comparator, Elem2 Item, Elem* List) -> positive Index determ.

tryGetIndexEq: : (predicate_dt Eq, Elem2 Item, Elem* List) -> positive Index determ.

Get Index of Item in the List. Index is zero based. Fails if Item is not found.

tryGetMemberBy: : (comparator Comparator, Test Value, Elem* List) -> Elem determ.

(74)

tryGetMemberEq: : (predicate_dt Eq, Test Value, Elem*

List) -> Elem determ.

Succeds if Value is member of List.

tryGetNth: : (positive Index, Elem* List) -> Elem Item de- term.

Return Item of List by Index. Index is zero based. Fails if the list is too short.

tryLastItem: : (Elem* List) -> Elem LastItem determ.

Get the LastItem from the List. Fails if List is empty.

union: : (Elem* ListA, Elem* ListB) -> Elem* UnionAB.

unionBy: : (comparator Comparator, Elem* ListA, Elem*

ListB) -> Elem* UnionAB.

unionEq: : (predicate_dt Eq, Elem* ListA, Elem* ListB) ->

Elem* UnionAB.

Returns union of ListA and ListB.

unzip: : (tuple*, A* AList [out], B* BList [out]).

Returns the the lists AList and BList from list of paired val- ues tuple(A, B).

unzip: : (tuple*, A* AList [out], B* BList [out], C* CList [out]).

Returns the the lists AList and BList from list of paired val- ues tuple(A, B).

zip: : (A* AList, B* BList) -> tuple*.

Returns the list of paired values tuple(A, B) from the lists AList and BList.

zip: : (A* AList, B* BList, C* CList) -> tuple*.

Returns the list of trippled values tuple(A, B, C) from the lists AList, BList and CList.

zipHead_nd: : (A* Alist, B* Blist) -> tuple nondeterm.

Returns the paired values tuple(A, B) from the lists AList and BList, ignoring misaligned tails.

zip_nd: : (A* AList, B* BList) -> tuple nondeterm.

Returns the paired values tuple(A, B) from the lists AList and BList.

(75)

questa classe. Costruiamo come al solito un nuovo proget- to usandoProject->New, chiamiamo questo nuovo progetto provalist, compiliamo, aggiungiamo un nuovo package chia- mato packscheda ed inseriamo in esso il form schedaform sotto riportato

Attiviamo la voce del menu File->New ed associamo a essa la seguente procedura:

(76)

Associamo alla pressione del tasto Push Button la seguente azione

Dobbiamo osservare l’uso del predicato append della clas- se list, detta classe è priva del costruttore new, quindi non possiamo istanziare dei suoi oggetti ma richiamiamo diretta- mente i suoi predicati mediante l’uso dei “::”. Da osservare che append richiede due parametri che sono entrambi delle liste, alla prima lista verrà appesa la seconda ed il risultato verrà restituito per essere inserito nella variabile Lista, quin- di non possiamo prendere direttamente il contenuto della casella di testo edit_ctl ma bisogna trasformare questi in una lista.

Le caselle di testo sono degli oggetti della classe editControl , di questo oggetto usiamo solo il predicato getText che è ereditato dalla classe Window, ecco che cosa

ho trovato nell’Help a proposito di questo predicato:

(77)

LLIsta = listbox_ctl:getAll(),

listbox_ctl:clearAll(),

listbox_ctl:addList(Lista).

(78)
(79)

backtracking, 65 clausola terminale, 30 clausole di Horn, 28 clausole ricorsive, 30 fatti-funtore, 29 fatti-variabile, 29 liste, 57

toTerm, 34 toterm, 34

79

(80)
(81)

81

Riferimenti

Documenti correlati

[r]

[r]

Similarly, each time we add another level of random shortcuts to the skip list, we cut the search time roughly in half, except for a constant overhead, so after O(log n) levels,

La sintassi di Prolog ci permettere di definire ed utilizzare strutture di dati: dobbiamo decidere la rappresentazione (come insieme di termini) e poi definire i costruttori,

[r]

[r]

 When a left extreme in encountered, insert the y- value range into an I-BST and check

H eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee W8eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeAf U8 6HI eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeW... g7