6.2        Linguaggi di programmazione

Nella memoria le istruzioni sono in “linguaggio macchina”, qui sotto c'è un frammento di programma su PC di 15 bytes.

Indirizzo      contenuto       Istruzione in Assembler
                 della memoria 
1329:0100   4D         DEC     BP
1329:0101   5A         POP     DX
1329:0102   9F         LAHF 
1329:0103   01AB0000   ADD     [BP+DI+0000],BP
1329:0107   0004       ADD     [SI],AL
1329:0109   0000       ADD     [BX+SI],AL 
1329:010B   00FF       ADD     BH,BH 
1329:010D   FF00       INC     WORD PTR [BX+SI]

I programmi, cioè le istruzioni fornite al computer sono dei file di testo, detti sorgenti, contenenti frasi di un linguaggio con regole sintattiche precise. A differenza dei linguaggi naturali, la maggior parte dei linguaggi di programmazione contengono solo frasi imperative, e dichiarative; alcuni linguaggi si basano solamente su frasi dichiarative.

Le frasi dichiarative descrivono i dati che il programma elabora, sia quelli non modificabili (costanti), che quelli modificabili durante l’elaborazione (variabili), quali contatori, aree di totalizzazione, ecc... I dati sono individuati da un nome, cui corrisponde una opportuna porzione di memoria .

Le frasi imperative sono istruzioni che elaborano i dati (ADD, MOVE, IF, ...).

Ad esempio:  ADD IMPORTO TO TOTALE_IMPORTO

IL primo vantaggio di un linguaggio di programmazione è che le informazioni nella memoria sono accessibili per nome (variabile o campo, in inglese field), e non pìù per indirizzo numerico (è il programma che traduce in linguaggio macchina che ci pensa), il secondo vantaggio è che è più facile creare un programma perché ci si può concentrare su ciò che si vuole ottenere, piuttosto che su come ottenerlo.

Qui di seguito sono esaminati alcuni dei più significativi, e più usati linguaggi di programmazione.

Si possono classificare i più comuni linguaggi utilizzati in ordine di complessità ed efficacia decrescente:

Linguaggio

Livello del linguaggio

Note

Macchina

 

Solo un disperato scrive in linguaggio macchina

Assemblatori

Basso

Per scrivere OS e programmi che lavorano velocemente

C, C++, JAVA

Medio

Per scrivere OS e programmi che lavorano velocemente

COBOL

Alto

Applicazioni commerciali

FORTRAN

Medio-alto

Applicazioni scientifiche

BASIC

Alto

Versatile

LISP, PROLOG

Medio

Per applicazioni di Intelligenza Artificiale

Tabella 61

L'utilizzo dell'uno, piuttosto che dell'altro dipende da ciò che si vuol ottenere: un programma che gestisce una scheda audio, sarà sviluppato in Assembler o C, perché deve essere efficiente e compatto. Una procedura commerciale su grandi sistemi (Mainframe) sarà sviluppata in COBOL . Un programma di simulazione scientifica probabilmente sarà scritto in FORTRAN. VISUAL BASIC è ideale per creare programmi che interagiscono con l'utilizzatore, non hanno particolari esigenze di performance e soprattutto devono essere messi in esercizio in fretta.

6.2.1            Modo di eseguire i programmi

I programmi, per essere eseguiti, devono essere convertire in linguaggio macchina, ciò avviene tramite programmi, detti compilatori, che trasformano le istruzioni in istruzioni di macchina. Questa operazione può dare origine ad un programma cosiddetto eseguibile (come lo sono Word, Excel, ecc.), oppure le istruzioni sono interpretate, cioè tradotte in linguaggio macchina, prima di essere eseguite, come nel caso dei VBscript e Javascript presenti in certe pagine INTERNET. Alcuni compilatori possono produrre, invece di istruzioni in linguaggio macchina, un programma in codice particolare detto p-code . Il p-code, sviluppato dalla  University of California, San Diego (UCSD) agli inizi del 1970, è il codice di una "macchina virtuale", e come tale può girare su qualsiasi calcolatore, a patto che sia disponibile un interprete p-code. Il vantaggio è la portabilità dei programmi, l'efficienza di questi, pur essendo inferiore a quella dei programmi compilati, è superiore a quella dei programmi interpretati.

6.2.2            I linguaggi assemblatori

Sono i più vicini alla struttura delle istruzioni del calcolatore.

Il sorgente di un programma in Assembler è formati da linee di testo contenenti:

·           Direttive al programma traduttore

·           Dichiarazioni di variabile e di costanti

·           Istruzioni

Ogni riga è generalmente formata da più parti separate da uno o più spazi:

etichetta   OP  Operando1,…,Operandon  Commento

Dove etichetta è un eventuale nome utilizzabile nelle istruzioni di salto o il nome di una variabile o di una costante. OP è il nome di un’istruzione, di una direttiva all’assemblatore o il codice di una dichiarazione di variabile o costante. OP di regola è l’unica parte obbligatoria.

Operando1,…,Operandon dipendono dalla struttura di OP, ci sono istruzioni con 1, 2 o nessun operando. Infine commento è facoltativo, ma è un costituente importante ai fini della documentazione di un programma.

In genere i compilatori Assembler permettono di scrivere delle macro, cioè sequenze di istruzioni, in cui gli operandi possono essere parametrizzati. Lo scopo delle macro, il cui nome è usato come un'istruzione, è di evitare la scrittura di sequenze simili di istruzioni.

Esempio:
         MACRO
&LAB     SOMMA  &ADD1,&ADD2           *  &ADD1 = &ADD1 + &ADD2
         L      R1,&ADD1              *   CARICO TOTALIZZATORE IN REG. 1
         A      R1,&ADD2              *  SOMMO ADDENDO AL REG. 1
         ST     R1,&ADD1              *  DA REG. 1 A TOTALIZZATORE
         MEND
....
         SOMMA  TOT,IMPORTO
....

Gli pseudooperandi MACRO e MEND racchiudono il prototipo della macro SOMMA, il compilatore espande l'istruzione SOMMA sostituendo nel prototipo gli operandi parametrizzati &ADD1 e &ADD2 con TOT e IMPORTO  rispettivamente.

Con riferimento ad un linguaggio assemblatore con solo due istruzioni, un salto su condizione e la sottrazione, la somma di due campi A e B, con l'ausilio di un campo C per i passaggi intermedi, è la seguente (tenuto conto che dopo l’istruzioione SUB V1,V2, il campo V1 conterrà V1 - V2):

Istruzione

Contenuto di A

Contenuto di B

Contenuto di C

 

37

13

SUB C,C

37

13

0

SUB C,B

37

13

-13

SUB A,C

50

13

-13

Figura 62

6.2.3            COBOL

Il COBOL  ( COmmon Business ­Oriented Language ) è stato sviluppato nel 1959. Nonostante la sua età, è ancora uno dei linguaggi più usati per le applicazioni commerciali. COBOL è un linguaggio standardizzato disponibile su molti computer: lo stesso sorgente, con minime variazioni  può essere compilato ed eseguito su diversi computer, dal mainframes al personal computers. Le istruzioni del COBOL sono in linguaggio similinglese. Questa caratteristica permette di imparare e scrivere programmi in modo piuttosto semplice.

Tutti i programmi COBOL  hanno obbligatoriamente quattro parti (divisions), ognuna con uno specifico compito e nell'ordine in cui compaiono qui di seguito:

·                                        Identification Division ­Identifica il programma; può anche contenere una descrizione del programma.

·                                        Environment Division ­ Definisce i file utilizzati dal programma, il calcolatore su cui è compilato ed il calcolatore su cui sarà eseguito.

·                                        Data Division ­ Contiene la descrizione dei dati di input e output.

·                                        Procedure Division ­ Contiene le istruzioni del programma.

All'interno delle DIVISION ci possono essere SECTION e paragrafi.

I  programmi COBOL  sono scritti su linee con tracciato fisso:

·                                         Colonne 1 - 6: sono utilizzate, facoltativamente,  per numerare le righe.

·                                        Colonna 7: se presente *, è un commento. Il simbolo / indica alla stampante di andare a pagina nuova. Altri caratteri sono interpretati come continuazione di una costante della riga precedente. 

·                                        Colonne 8 - 11: è detta "Area A"; in essa devono iniziare DIVISION, SECTION, e i paragrafi.

·                                        Colonne 12 - 72: è detta "Area B"; è l'area riservata alle istruzioni.

·                                        Colonne 73 - 80: zona facoltativa utilizzabile per identificare il programma

6.2.3.1              Identification Division

In questa divisione sono fornite informazioni sul programma. L'unico paragrafo necessario è il PROGRAM-ID. Opzionalmente si può indicare l'AUTHOR, l'INSTALLATION; la DATE-WRITTEN, la DATE-COMPILED e la SECURITY.

6.2.3.2                Environment Division

E' la parte del COBOL  dipendente dalla macchina. Contiene due sezioni: la configuration section e la input-output section. La configuration section indica tramite il paragrafo source computer il computer usato per compilare il programma e col paragrafo object computer il computer che sarà utilizzato per eseguire il  programma.

       ENVIRONMENT DIVISION.CONFIGURATION SECTION.
         SOURCE-COMPUTER. IBM-ES900.
         OBJECT-COMPUTER. VAX-8800.

Nell'input-output section sono fornite informazioni sui dispositivi di trattamento dei dati utilizzati nel programma. Qui di seguito un esempio.

      INPUT-OUTPUT SECTION.
      FILE-CONTROL.
      SELECT EMPLOYEE-FILE ASSIGN TO C:\EMPFILE.
      SELECT TRANS-FILE ASSIGN TO PRINTER.
      ORGANIZATION IS LINE SEQUENTIAL.

6.2.3.3              Data Division

Nella DATA DIVISION sono descritti i dati utilizzati nel programma. Nella FILE SECTION sono descritti i formati dei record contenuti nei files di input e di output. La WORKING STORAGE SECTION è riservata alla descrizione delle aree di lavoro del programma e delle costanti. La LINKAGE SECTION è presente quando il programma riceve o produce dei dati non tramite file, ma da un altro programma, tramite la memoria del calcolatore, e descrive il formato di questi dati.

La definizione dei dati ha la struttura (fra parentesi [ ] clausole opzionali):

        lv  nome [REDEFINES nome].
        lv  nome [REDEFINES nome] PICTURE schema [VALUE 'valore'].

Dove lv è un numero che indica il livello del campo. Il livello 01 inizia nell'area A, i livello da da 02 a 49 indicano una sottodivisione  del soprastante campo a livello 01, ed iniziano nell'area B.

PICTURE é la parola chiave che precede schema ossia ampiezza e tipo di campo; esso può essere di tipo alfabetico, alfanumerico o numerico, rispettivamente indicati con A, X, e 9. La lunghezza è data dal numero  di A, X, o 9 presenti. Per i numeri, inoltre è possibile indicare i decimali ed il segno.

La prima forma  è relativa a campi che sono sottolivellati, il suo tipo è X (alfanumerico) e la lunghezza è la somma delle lunghezze dei suoi sottolivelli. Esempio:

       01  VERSAMENTO.
           05  VERSATORE PICTURE X(30).
           05  DATA_VERSAMENTO.
               10 ANNO PICTURE 9999.
               10 MESE PICTURE 99.
               10 GIORNO PICTURE 99.
           05  IMPORTO PICTURE 999V99.

6.2.3.4              Procedure Division

E' la parte in cui è eseguita l'elaborazione dei dati. L'istruzione OPEN prepara ad accedere ai file riservandone l'utilizzo al programma; tramite l'istruzione READ i dati di input vengono portati in memoria e con l'istruzione WRITE dalla memoria sono mandati su file. L'istruzione CLOSE termina le operazioni sul file, di fatto questo è disponibile ad altre elaborazioni o altri programmi.

Le istruzioni condizionali sono PERFORM UNTIL e IF ... THEN ... ELSE, le istruzioni di assegnazione sono:

           MOVE     nome_di_dato/costante TO   nome_di_dato
           ADD      nome_di_dato/costante TO   nome_di_dato
           SUBTRACT nome_di_dato/costante FROM nome_di_dato
           MULTIPLY nome_di_dato/costante BY   nome_di_dato
           DIVIDE   nome_di_dato/costante INTO nome_di_dato
           DIVIDE   nome_di_dato/costante INTO nome_di_dato

Infine i comandi STOP-RUN ed EXIT rispettivamente terminano il programma o il sottoprogramma.

6.2.4            FORTRAN

Il Fortran (FORmula TRANslation) è un linguaggio general purpose adatto cioè per qualsiasi tipo di problema, ma è particolarmente adatto per i calcoli matematici. Il Fortran è nato nel 1950 alla IBM ed ha avuto da allora molte versioni.

Un programma Fortran è una sequenza di linee di of testo con una sintassi fissa [1] :

Col. 1            Spazio, o "c" o "*" per commenti
Col. 2-5          Etichetta opzionale
Col. 6            Se diverso da blank indica continuazione della linea precedente
Col. 7-72         Istruzioni
Col. 73-80        Numerazione

Un semplice esempio:

      program circle
      real r, area
c Questo programma legge un numero reale e stampa
c l’area del circolo di raggio r.
      write (*,*) 'Give radius r:'
      read  (*,*) r
      area = 3.14159*r*r
      write (*,*) 'Area = ', area
      stop
      end

Un programma  Fortran generalmente consiste di una parte principale ed eventuali sottoprogrammi. La struttura del programma principale è:

      Nome del programma     es. program circle
      Dichiarazioni          es. real r, area
      Istruzioni             es. write (*,*) 'Give radius r:'
      stop
      end

I nomi di variabile sono da 1 a 6 caratteri scelti fra {ab…z01…9}. Il primo carattere deve essere una  lettera. Ogni variable deve essere dichiarata esplicitamente e se ne deve indicare il tipo; i tipi più comuni sono:  integer, real, double precision, complex, logical, character.

L'istruzione condizionale può assumere diverse forme, la piu' generale è:

      if (logical expression) then
         statements
      elseif (logical expression) then
        istruzioni
        :
      else
        istruzioni
        :
      endif

Nelle forme più semplici possono mancare i costrutti elseif ed else.

La più semplice, che deve essere scritta su una sola linea, è:

      if (espressione logica) istruzione

Esempio (valore assoluto di x):

      if (x .LT. 0) x = -x

Nell'esempio che segue viene effettuata la somma dei numeri interi da 1 ad n (si presume che ad n sia stato assegnato un valore in precedenza):

      integer i, n, sum
      sum = 0
      do 10 i = 1, n
         sum = sum + i
         write(*,*) 'i =', i
         write(*,*) 'sum =', sum
  10  continue

Il numero 10 è una etichetta label. Le istruzioni comprese fra do 10 … e 10  continue sono ripetute fino a quando i, che è incrementato di 1 ad ogni ciclo, diventa uguale ad n.   

6.2.5            BASIC

VISUAL BASIC è un linguaggio di programmazione di alto livello, evolutosi dalle prime versioni per DOS chiamate semplicemente BASIC (Beginners' All purpose Symbolic Instruction Code). E' un linguaggio molto semplice da apprendere, in quanto le istruzioni sono parole della lingua inglese. VISUAL BASIC permette una programmazione guidata dagli eventi, lo sviluppo dei programmi si effettua in ambiente grafico.

6.2.6            C

Il linguaggio C è stato definito nel testo, ormai classico, di Kernigan e Ritchie: "The C Programming language" e sviluppato da Dennis Ritchie dei laboratori Bell inizialmente per l'elaboratore Digital PDP-11 su sistema operativo UNIX. Nel dicembre 1989 ne è stato dato lo standard ANSI.

C++ è il tradizionale linguaggio con qualche costrutto addizionale orientato alla programmazione ad oggetti. Fra le maggiori caratteristiche del linguaggio C ci sono la possibilità di definire tipi di dati, l'efficacia del codice macchina ottenuto e la capacità di sviluppare software di grandi dimensioni.

In C i blocchi di istruzione sono racchiusi fra parentesi graffe: {}, in particolare delimitano l'ambito delle istruzioni if, for e while; la singola istruzione è delimitata da ";".

Alcuni costrutti sono criptici, ad esempio:

i++, i--  invece dei più leggibili i=i+1 e i=i-1,

j -= h invece di j = j-h

Molte estensioni del linguaggio, quali le istruzioni di input/output, il trattamento delle stringhe di caratteri, ed altro, sono fornite in librerie da includere nel sorgente del programma.

La vasta diffusione e popolarità del linguaggio C è dovuta in buona parte alla sua gratuita cessione alle università.

6.2.7            Linguaggi ad oggetti

Gli oggetti sono una evoluzione delle librerie, ma sono "attivi", cioè possono memorizzare e variare al loro interno delle informazioni e possono attivare delle funzioni su sollecitazione di particolari eventi (event driven). Nella terminologia degli oggetti le funzioni sono dette metodi, le informazioni proprietà, ed eventi le sollecitazioni a cui essi reagiscono.

La classe di un oggetto è la sua definizione, l'istanza dell'oggetto è l'oggetto utilizzato dal programma. Di un oggetto se ne possono creare più istanze.

Esempio:

class automobile
  proprietario string
  marca string
endclass
Actual instance 1
  proprietario Beatrice
  marca Morris Mascot
End
Actual instance 2
  proprietario John
  marca Rolls Royce
End

Un linguaggio può essere considerato orientato agli oggetti (OOP Object Oriented Programming) se ha le seguenti caratteristiche: incapsulazione, ereditarietà, e identità.

§         Incapsulazione: è la caratteristica per cui si conosce dell'oggetto i metodi, le proprietà, e gli eventi, ma non come questi sono realizzati.

§         Ereditarietà: un Oggetto può essere strutturato in forma gerarchica, un oggetto eredita proprietà e metodi dai predecessori.

§         Identità: l'dentità dell'oggetto rimane anche al variare dei suoi attributi.

6.2.7.1              Proprietà

Le proprietà di un Oggetto sono molteplici e dipendono dal tipo di oggetto. Un oggetto grafico avrà  dimensioni, posizionamento sul form, colore, bordi, sequenza di attivazione, visibilità, abilitazione, ecc... Le proprietà possono essere determinate al momento della preparazione dell'interfaccia utente, oppure variate dal programma.

6.2.7.2              Eventi

Gli eventi sono le azioni dell'utilizzatore sull'oggetto, ad esempio la pressione del tasto del mouse. La "reazione" del programma all'evento è una porzione di programma, associata all'evento, che effettua qualche particolare azione.

6.2.7.3              Metodi

I metodi sono delle azioni che l'oggetto compie se attivato da appositi comandi del programma. Alcuni metodi sono nativi, altri, quelli legati agli eventi, sono scritti dal programmatore.

6.2.8            Il PROLOG

Il Prolog  (PROgramming in LOGic) è stato sviluppato all’Università di Marsiglia da Alain Colmerauer all’inizio degli anni 1970, come uno strumento di programmazione basato sulla logica, più precisamente su un sottoinsieme del calcolo dei predicati. Prolog è un linguaggio dichiarativo, in esso non vi è una sequenza di azioni, ma una raccolta di predicati (o fatti) con delle regole: in terminologia logica (v. 1.3.1 e 1.3.3 ) i predicati sono proposizioni, proposizioni con variabili ed enunciati [2] (con valore di verità "vero") e le regole sono implicazioni; l'esempio del paragrafo 1.3.3 :

Φ = {" piove" , "piove > strada bagnata"}

β = "strada bagnata" 

tradotto nella sintassi Prolog  ciò diventa:

piove.

bagnato:-piove.

L'esecuzione del programma è una richiesta a Prolog  di dedurre dei fatti dall'insieme di informazioni che Prolog conosce, cioè l'insieme di predicati e di regole comunicate al programma; nell'esempio precedente vi è un predicato "piove" ed una regola "è bagnato se piove"; una possibile richiesta è:

goal bagnato.

La risposta di Prolog  è:

yes

Mentre nel calcolo proposizionale si può dedurre unicamente il valore di verità di una proposizione, come nell'esempio visto, Prolog , invece, è in grado di dedurre, se la domanda è un predicato contenente variabili, i valori che soddisfano il predicato. Il cuore di Prolog è un motore di inferenza, cioè un (sotto)programma per ragionare logicamente sulle informazione. Prolog cerca di inferire che un'ipotesi è vera (la domanda che è stata posta), interrogando la collezione di informazione già note per essere vere. La risposta comprende tutte le soluzioni possibili.

6.2.8.1              Fatti e Regole

I predicati possono esprimere sia proprietà degli oggetti che relazioni; in linguaggio naturale proprietà sono "l'erba è verde" e "Maria è una ragazza.", mentre sono relazioni, ad esempio: "a Mario piace guidare", "Parigi è la capitale della Francia".

L'assunzione basilare è che i predicati sono ciò che è conosciuto, implicitamente ciò che è conosciuto è vero.

Nella sintassi di Prolog  un predicato si scrive con un nome di predicato seguito fra parentesi dall'oggetto o dagli oggetti su cui agisce; il tutto chiuso con un punto:

tipo(ferrari,sportiva).
tipo(maserati,sportiva).
tipo(fiat,famigliare).
tipo(renault,utilitaria).
piace(marco,auto).
piace(elena,auto).
piace(anna,bici).

Le regole sono predicati in cui un fatto è "vero" se uno o più altri fatti sono veri. La regola che definisce quando "piace guidare a Mario" potrebbe essere la seguente: "a Mario piace guidare se l'automobile è sportiva". Quindi le regole sono formate da due parti, la prima (testa) è un predicato che è reso vero dalla seconda (corpo), separata dalla prima tramite i simboli ":-" (due punti meno col significato di se), è:

piace(anna,auto):-tipo(Automobile,famigliare);tipo(Automobile,utilitaria).
piace(mario,auto):-tipo(Automobile,sportiva),Automobile 

La prima regola afferma che ad anna piace l'auto se e' famigliare o utilitaria, l'alternativa è indicata in Prolog  col segno ";". Per la seconda regola, a mario piacciono le auto sportive purchè non siano ferrari; purchè in questo caso è tradotto con l'operatore logico e, che in Prolg è indicato con il segno ",". Non è per poco rispetto verso Anna, Mario che in Prolog compaiono in minuscolo: in minuscolo si indicano i fatti conosciuti, mentre le variabili hanno un nome che inizia con una lettera maiuscola, come la variabile Automobile che compare nelle regole.

Le regole permettono la deduzione di fatti da altri fatti, ma esse possono essere pensate come procedure. per chiedere a Prolog  di compiere azioni diverse dal provare dei fatti, quali la scrittura di qualcosa o la creazione di un archivio, e in genere, ciò che un linguaggio di programmazione può fare.

6.2.8.2              Domande

Una volta fornito a Prolog  un insieme di predicati, gli si possono porre domande che riguardano tali predicati; dall'esempio del paragrafo precedente, alcune domande potrebbero essere:

Domanda in linguaggio naturale

Domanda Prolog

Risposta

Cosa piace ad Anna

piace(anna,Cosa)

Cosa=bici

Cosa=auto

Cosa=auto

3 Solutions

Cosa piace a Chi

piace(Chi,Cosa)

Chi=antonio, Cosa=auto

Chi=carla, Cosa=auto

Chi=anna, Cosa=bici

Chi=anna, Cosa=auto

Chi=anna, Cosa=auto

Chi=mario, Cosa=auto

6 Solutions

Piacciono a Mario le auto

piace(mario,auto)

yes

Piacciono a Mario le biciclette

piace(mario,bici)

no

C'è qualcuno a cui piace la bici

piace(_,bici)

yes

Esiste un catorcio di macchina

tipo(Marca,catorcio)

No Solution

Figura 63

Prolog  per rispondere ad una domanda esamina i predicati che conosce: il caso più semplice è quello in cui la domanda non contiene variabili, come in piace(mario,auto), in questo caso Prolog cerca se esiste il predicato piace(mario,auto) o una regola la cui testa sia il predicato. Se non trova nulla la risposta è no, altrimenti, se esiste il predicato la risposta è yes, se esiste la regola e la coda di essa risulta vera, la risposta è yes, altrimenti è no.

Se la domanda contiene variabili, Prolog  sostituisce alla variabile, via via il valore che ricava dai fatti, la risposta invece di essere yes o no è l'elencazione degli attributi che soddisfano la variabile oppure: No Solution. Alla domanda piace(anna,Cosa), Prolog ha risposto due volte Cosa=auto, ciò deriva dalla caratteristica di Prolog di cercare tutte le soluzioni, infatti la regola:

piace(anna,auto):-tipo(Automobile,famigliare);tipo(Automobile,utilitaria).

é soddisfatta due volte, poiché fra i fatti ci sono una automobile famigliare ed una automobile utilitaria.

Il segno "_"  indica una variabile anonima per rispondere a domande generiche.

Prolog  esamina tutti i fatti per rispondere, tranne quando la domanda è senza variabili, perciò al primo predicato verificato è in grado di rispondere yes, e quindi può interrompere la ricerca.

In Prolog  le variabili sono gestite dal motore di inferenza, esse nascono libere (free), e nel corso dell'elaborazione Prolog le lega (bound) per stabilire se soddisfano la richiesta, finita l'elaborazione esse ridiventano libere. La cosa che più si avvicina al concetto di variabile dei linguaggi tradizionali, è il fatto, ed i fatti si possono aggiungere alla collezione di fatti e regole tramite un apposito predicato (assert).

6.2.8.3              PROLOG come linguaggio procedurale

La caratteristica di Prolog  di cercare regole o fatti che soddisfino la domanda, è la base del suo utilizzo procedurale, in particolare se la domanda è relativa ad una regola plurima, cioè stessa testa e corpi diversi, Prolog verificherà la prima regola (quindi l'ordine delle regole è talvolta essenziale) se essa non è verificata, procederà con la regola successiva, ad esempio:

ciclo(10):-!.                                /* variabile = 10 termina      */
ciclo(Counter):-NewCounter=Counter + 1,      /*   aggiorno contatore di ciclo */
                random(Rnd),                 /* genero un numero a caso     */
                write(NewCounter,"\t",Rnd),nl,  
                ciclo(NewCounter).           /* riciclo                     */
trova:-write("Inizio della generazione di numeri casuali\n"),fail.
trova:-ciclo(0),fail.
trova:-write("Fine della generazione di numeri casuali\n"),exit.
goal trova.

La domanda è trova, Prolog  verifica la prima regola trova, in questa il predicato write produce una scritta sul video e risulta non verificato, a causa del predicato fail. Il predicato fail ha lo scopo forzare Prolog a proseguire e verifica quindi la seconda regola trova e poi finalmente la terza.

La seconda trova verifica il predicato ciclo che genera 10 numeri casuali, infatti la prima regola ciclo termina il ciclo, la seconda genera un numero a caso, tramite il predicato random, incrementa il contatore del ciclo, scrive il numero casuale ed infine ripete il ciclo.

La regola ciclo(10):-!. termina il ciclo  tramite il predicato ! (cut), il cui scopo è di terminare la verifica della regola. Il predicato ! è utilizzato per lo scopo appena visto e quando interessa conoscere se c'è una soluzione, evitando così la perdita di tempo per trovarle tutte.

Il predicato exit evita la visualizzazione della risposta di Prolog . Infine il predicato nl permette l'avanzamento di una riga (in alternativa ai caratteri "\n" nel predicato write).

6.2.8.4              PROLOG e la conoscenza implicita

Nelle regole e nei fatti talvolta è presente della "conoscenza implicita":  essa è o nel significato del predicato, ad esempio dati i fatti prima(a,b) e prima(b,c), la conoscenza implicita è prima(a,c) perché prima è una relazione di ordine, o nelle relazioni fra fatti diversi, ad esempio da fatti e regole del paragrafo 6.2.8.1 si capisce che a Mario piacciono le  maserati, e a Elena piacciono tutte le automobili. Ma non c'è una regola o un fatto che dica qualcosa del genere: se a Tizio piacciono le Automobili,  la Marca dell'automobile preferita è …  Prolog  permette di generare dei fatti, tramite il predicato assert(...), quindi potrebbe generare il fatto marca_preferita(persona,marca), e poi elencarlo. 

Le regole relative ad Anna e Carlo fanno riferimento al tipo di auto, quindi se la regola è verificata, Prolog  ha trovato la Marca dell'automobile, si possono modificare le due precedenti regole, come segue:

piace(anna,auto):-  tipo(Automobile,famigliare),
                    assert(marca_preferita(anna,Automobile));
                    tipo(Automobile,utilitaria),
                    assert(marca_preferita(anna,Automobile)).
piace(carlo,auto):- tipo(Automobile,sportiva),Automobile <> "ferrari",
                    assert(marca_preferita(carlo,Automobile)).
Questo vale solamente per Anna e Carlo, per tutti gli altri occorre aggiungere (in coda) un'ulteriore regola:
piace(X,auto):-tipo(Auto,_),X <> "anna",X <> "carlo",
                                   assert(marca_preferita(X,Auto)).
Infine occorre scrivere le regole "procedurali" per eseguire il tutto, qualcosa di simile a ciò che segue:

elenco_marche(X):-  piace(X,auto),fail.
elenco_marche(_):-  marca_preferita(X,Y),
                    write(X," gradisce la ",Y),nl,fail.
elenco_marche(_):-  write("--------------"),nl,exit.
goal elenco_marche(anna).

La risposta di Prolog  è:

anna gradisce la fiat

anna gradisce la renault

--------------

La prima regola elenco_marche genera tutte le preferenze (di Anna), e la seconda le stampa.

La potenza di Prolog  è nella capacità di estrarre la "conoscenza implicita" che è presente nei fatti, mediante opportuni predicati; questi in sostanza formalizzano le relazioni esistenti fra i fatti, ad esempio le relazioni d'ordine che il predicato prima (A è prima di B) sottende. L'esempio che segue vuole è un programma che verifica l'esistenza di cicli in un insieme di attività, di cui sono date le precedenze tramite il predicato prima(). I fatti sono:

prima(ideazione,pianificazione).
prima(pianificazione,pubblicità). 
prima(ideazione,"ricerca materiale").
prima("ricerca materiale",stesura).
prima(pubblicità,ideazione).     % introduce un ciclo
prima(pianificazione,stesura).
prima(stesura,correzione).
prima(correzione,stampa).
prima(pubblicità,distribuzione).
prima(stampa,distribuzione).

I predicati di ricerca dei cicli sono:

trovacicli(X):-attivita(X,Y,[]).
attivita(Prima,Dopo,ListaLavori):-prima(Prima,Dopo),
                                  not(member(Dopo,ListaLavori)),
                                  prima(Dopo,NextDopo),
                                  attivita(Dopo,NextDopo,[Dopo|ListaLavori]).
attivita(_,Dopo,ListaLavori):-member(Dopo,ListaLavori), 
                              write("Ciclo: "),nl,
                              writelist([Dopo|ListaLavori]),fail.
attivita(_,_,[]):-write("--- Fine ---"),nl,
                  exit.

Il predicato trovacicli è utilizzato per la ricerca, il suo oggetto è una attività di partenza; il primo dei predicati attivita "scorre" la sequenza di attività, se una attività è già stata trovata (predicato member), fallisce, altrimenti prosegue la ricerca inserendo l'attività in una lista di attività.

Il secondo predicato attivita agisce dopo il primo, ed ha come oggetti le variabili Dopo e ListaLavori ereditate dal primo predicato attivita, in particolare se questo è fallito per il predicato not(member(Dopo,ListaLavori)), Dopo conterrà l'attività che provoca il ciclo, e ListaLavori l'elenco delle attività che compongono il ciclo, e queste verranno stampate.

Alla domanda:

GOAL trovacicli(ideazione).

Prolog risponde:

Ciclo:
pianificazione
ideazione
pubblicità
pianificazione
--- Fine ---

Alla domanda:

GOAL trovacicli(correzione).

Prolog, non trovand cicli dopo l'attività "correzione",  risponde:
--- Fine ---

In questo programma si è utilizzata una lista per elencare le attività. Le liste sono una struttura di dati che può essere usata ricorsivamente sfruttando la definizione:

Lista = [Testa o primo elemento della lista | Coda o resto della lista]

L' operatore | permette sia la costruire delle liste, che il loro trattamento, un esempio del primo caso è la clausola writelist([Dopo|ListaLavori]):  l'oggetto di writelist è la lista formata dall'elemento Dopo, seguita dalla lista ListaLavori. Sfortunatamente ci sono pochi predicati nativi per trattare le liste, è necessario scriverli, o utilizzare delle definizioni da inserire tramite il comando Prolog include, come è stato fatto nell'esempio precedente con i due predicati:

member(Testa, [Testa|_]).
member(Testa, [_|Coda]):-member(Testa,Coda).
writelist([]).
writelist([Testa|Coda]):-write(Testa),nl,writelist(Coda).

Questi chiariscono come trattare ricorsivamente le liste, ad esempio il predicato member verifica la presenza di un elemento in una lista: se l'elemento è il primo, viene verificato il primo predicato member, altrimenti la ricerca prosegue, ricorsivamente,  sul resto della lista.



[1] FORTRAN 90 ammette una sintassi meno vincolante.

[2] Si ricorda che una proposizione è anche detta relazione, e enunciato è una proposizione con valore di verità conosciuto.