Gioco e programmazione

Transcript

Gioco e programmazione
Gioco e programmazione
""
Lidia Stanganelli
Dipartimento di Informatica, Sistemistica e Telematica, Università di Genova
[email protected]
Esiste, in internet, una moltitudine di
giochi didattici per l’apprendimento di
discipline come la matematica, la
grammatica e anche le lingue
straniere. Quando invece ci si rivolge
ai giochi per l’insegnamento dei
linguaggi di programmazione il
materiale che si trova non è
altrettanto variegato come per le
discipline suddette. In questo lavoro si
presentano i risultati di uno studio su
come si possa trasmettere la
conoscenza relativa alla programmazione
attraverso
un’attività
“ludica”. In particolare, mostreremo
come possiamo dare i primi rudimenti
della programmazione ai neofiti
“giocando”. La risposta è usare un
linguaggio con il quale esprimere
concetti a un più elevato livello
rispetto a quelli della programmazione
imperativa, nei quali il concetto sia
simile a quello che concepisce
l’utilizzatore (sia universitario che
liceale) e non debba essere
ulteriormente specificato per essere
applicato.
There is in Internet a lot of educational
games for learning subjects like math,
grammar and foreign languages. But
when one turns to the games for teaching
programming languages material that is
not as varied as the disciplines mentioned
above. In this paper we present the results
of a study on how to transmit knowledge
on
programming
through
an
"entertaining". In particular, we show how
we can give the basics of programming for
beginners "playing." The answer is to use a
language with which to express concepts
at a higher level than those of imperative
programming, where the concept is similar
to what the user sees (both at university
and high school) and should not be further
specified to be applied.
If all you have is a hammer, every problem looks like a nail.
1. Introduzione
Dopo un’attenta ricerca nel mondo di internet siamo venuti a conoscenza del fatto che esiste un gran
numero di siti per l’apprendimento delle lingue, per qualsiasi livello ed età (Dienneti, English-4kids,
Funbrain). Si va dalla scuola elementare (Fact Monster) fino ad un livello elevato come quello universitario
(Dienneti). Quando si cercano giochi in questo ambito, la scelta è ampia, anche se molto spesso si trovano
Stanganelli L., Gioco e programmazione
Lingu@ggi 21.0, n. I, anno 2010
lo stesso tipo di giochi su siti diversi. Se ci immergiamo in una ricerca su come imparare un certo linguaggio
di programmazione anche qui i siti sono “infiniti”, ma appena si cercano giochi per imparare a
programmare non si trova altrettanto materiale, anzi sembra non essere stata proprio contemplata una
possibilità del tipo: imparare giocando. In particolare si trovano siti che insegnano come realizzare
videogiochi i quali sono orientati ad un’utenza generalmente già esperta.
È possibile pensare a diversi linguaggi di programmazione per avvicinarsi al mondo dei computer, non
solo da semplici utenti ma da “progettisti” in grado di realizzare tools per la propria attività, per diletto, per
interesse e così via. Negli ultimi cinquant’anni per trasmettere la disciplina della programmazione in modo
semplice ai neofiti sono stati utilizzati linguaggi come il Logo. Logo è un linguaggio di programmazione per
l’insegnamento di tutte le discipline, dalla matematica alla logica, dalla musica al disegno e naturalmente
anche la programmazione. Molto diffuso negli USA, a diversi gradi di istruzione, mentre in Italia l’interesse
verso questo linguaggio è stato mostrato da parte delle scuole di livello inferiore, nel mondo accademico
non ha avuto lo stesso successo, sebbene il suo utilizzo sia molteplice. Di questo linguaggio si discuterà
anche nel prossimo paragrafo quando parleremo di "linguaggi candidati" per insegnare/apprendere
giocando i concetti di programmazione.
Un linguaggio che si pone a un livello di espressività logico-matematica alto è il Prolog (Clocksin, Mellish
2003). Si tratta di un linguaggio al quale possono avvicinarsi tutti coloro che abbiano le capacità logicomatematiche di descrizione dei problemi. Infatti, al contrario dei linguaggi procedurali (come Pascal,
Fortran, C, etc.), e dei linguaggi ad oggetti (C++, Java, Ruby etc.), Prolog è utilizzato in modo particolare
nell’ambito della intelligenza artificiale (Nilsson 1998), come linguaggio di alto livello più vicino al modo di
pensare di un essere umano. Prolog ha l'enorme vantaggio di essere sintetico, fortemente espressivo e di
conservare il livello di astrazione giusto per poter essere compreso dall'essere umano.
Siccome esistono molti linguaggi di programmazione, nei prossimi paragrafi si farà una valutazione
comparata tra alcuni di questi considerandoli dal punto di vista della espressività, della concisione e del
livello di astrazione, tipiche caratteristiche che servono ad un neofita quando si addentra nello studio dei
fondamenti di programmazione senza essere distratto dai dettagli dei linguaggi di programmazione stessi.
Nel paragrafo successivo in particolare si affronterà questa valutazione comparata dei linguaggi
(procedurali e non), nel paragrafo 3 si illustreranno le prime tecniche di presentazione dei concetti tramite
il linguaggio dichiarativo prolog, nel paragrafo 4 si discuteranno le conclusioni e lo sviluppo futuro di questo
lavoro..
2. Un approccio comparato di alcuni linguaggi di programmazione per identificare similarità con
le attività di un gioco
Approcciare in maniera rigorosa e sistematica a un tema di tale vastità e complessità non è obiettivo di
questo lavoro oltre che essere molto impegnativo e complesso. Valutare comparativamente diversi
linguaggi non è una attività semplice anche perché molti di questi nascono in contesti storici diversi (alcuni
sono vecchi di decine e decine di anni), pensiamo che l'approccio ideale sia quello pragmatico: scegliamo
una semplice istruzione che comunica un concetto e osserviamo come questa viene rappresentata in vari
linguaggi. Dalla valutazione comparata delle diverse versioni scritte dello stesso concetto si evidenzierà
razionalmente quali linguaggi possono essere di ostacolo all'esposizione del concetto stesso.
Come esempio useremo un semplice concetto di somma fra due numeri C=A+B?
Si badi bene qui si tratta di esprimere un concetto. Qualcuno potrebbe affermare che è già espresso
dalla formula, la quale è anche un modello matematico di rappresentazione (in realtà la stessa formula
potrebbe essere rappresentata da un algoritmo ovvero da una sequenza di azioni elementari che portano al
risultato, ma supponiamo che ci basti questo livello di astrazione per accomunare la gran parte di persone
intorno al concetto, d'altro canto il nostro obiettivo è selezionare il linguaggio più espressivo). Allora
proviamo a dimostrare, per casi, che quella formula rappresenta il nostro migliore modo di partenza per
esprimere il concetto ed anche per scegliere il linguaggio adatto che la dovrà eseguire e per farlo proviamo
a fare il seguente esperimento: proviamo a scriverla in altri 12 linguaggi diversi anche provando a misurare i
tempi di scrittura, la difficoltà spesa, i concetti da spiegare, i pro ed i contro, etc., alla fine ne trarremo le
conclusioni. I linguaggi scelti per esprimere C=A+B sono Basic, C, C++, Java, Phyton, Smalltalk, Lisp, Ruby,
Perl, Shell, Pascal, Prolog.
BASIC
10 INPUT A
20 INPUT B
30 C=A+B
40 PRINT C
RUN
Tempo di scrittura: 15 secondi.
Concetti da spiegare: Numeri di linee, variabili, INPUT, PRINT, RUN.
Pro e Contro: BASIC è molto semplice per coloro i quali iniziano la programmazione ma è molto vecchio, di
concezione e carente sia nella sua architettura che nei costrutti linguistici posseduti. Visual Basic
compendia molto tali carenze ma comunque non è appropriato per supportare l'insegnamento di concetti e
continua ancora adesso ad essere un linguaggio non adatto per l'insegnamento dei concetti fondamentali
della programmazione.
C
#include <stdio.h>
int main(int argc, char*argv[])
{
int a,b,c;
scanf("%d",&a);
scanf("%d",&b);
c = a+b;
printf("%d\n",c);
}
%> gcc -o add add.c
%> ./add
Tempo di scrittura: circa tre minuti, debugging incluso.
Concetti da spiegare: le direttive del preprocessore (#include), il concetto di funzione (main), lo scambio
delle variabili (argc, argv ) ed il tipo del risultato di ritorno della funzione main (return types); variabili, tipi
(int); scanf (ed anche le sue limitazioni ed il formato di stampa tipizzato); printf, le stringhe di caratteri
(strings); puntatori (proprio così presto!!); compilazioni, parentesi (graffe) e terminatori (;) delle istruzioni.
Pro e Contro: C è stato costruito per programmatori esperti allo scopo di scrivere sistemi operativi,
compilatori ed altri strumenti software ed è questo il suo principale impiego. In questo contesto le sue
prestazioni sono eccellenti (presupponendo sia la scelta dell'algoritmo che degli skill buoni) e consente
l'accesso a basso livello dell'hardware della macchina. L'uso di C peraltro è frustrante per chi si avvicina alla
programmazione per la prima volta, a causa dell'uso dei puntatori e crea grandi confusioni, in quanto
questi sono essenziali già nell'uso dei primi algoritmi, inoltre l'utilizzo delle stringhe è carente se comparato
con quello di linguaggi più moderni (ad esempio C++) e la funzione scanf non è certamente la migliore per
essere insegnata e compresa in quanto presenta molti dettagli inspiegabili ai neofiti che ingenerano
confusione. Insomma sebbene C sia uno dei linguaggi fra i più importanti per i quali tutti i programmatori
dovrebbero avere una formazione, risulta complesso da insegnare ai neofiti: ci sono più dettagli del
linguaggio da insegnare che buoni concetti di programmazione che alla fine si perde troppo tempo attorno
ad essi correndo il rischio di trascurare i concetti.
Java
import java.io.*;
public class Addup
{
static public void main(String args[]) {
InputStreamReader stdin = new InputStreamReader(System.in);
BufferedReader console = new BufferedReader(stdin);
int i1 = 0,i2 = 0;
String s1,s2;
try {
Stanganelli L., Gioco e programmazione
Lingu@ggi 21.0, n. I, anno 2010
s1 = console.readLine();
i1 = Integer.parseInt(s1);
s2 = console.readLine();
i2 = Integer.parseInt(s2);
}
catch(IOException ioex) {
System.out.println("Input error");
System.exit(1);
}
catch(NumberFormatException nfex) {
System.out.println("\"" + nfex.getMessage() + "\" is not numeric");
System.exit(1);
}
System.out.println(i1 + " + " + i2 + " = " + (i1+i2));
System.exit(0);
}
}
%> javac Addup.java
%> java Addup
Tempo di scrittura: 20 minuti. La prima cosa che si nota è che questo codice non è perfettamente
equivalente al concetto di somma ma ha qualcosa in più. Ad esempio il controllo degli errori attraverso le
eccezioni. Ma Java rende difficile non fare il controllo attraverso le eccezioni, che una volta catturate,
possono anche essere utilizzate.
Concetti da spiegare: import, classes, semicolons braces; public, static, void, String, main args[];
InputStreamReader, BufferedReader, System.in; variables, types; try, catch, exceptions, readLine, parseInt;
System.out.println, compiling, running.
Pro e Contro: Java è un linguaggio utile per lo sviluppo cross-platform GUI, è una solida piattaforma per lo
sviluppo OO, ed ha un vasto e altamente evoluto insieme di librerie di classi. Attualmente è il linguaggio più
popolare. La vasta libreria di classi rende l’uso di questo linguaggio ostico. Java impone una mentalità
orientata agli oggetti, il controllo delle eccezioni e una forte tipizzazione, tutti lati positivi che rendono più
facile la creazione di grandi sistemi. Ma per piccoli problemi (come quelli affrontati in corsi di
programmazione introduttiva) questi elementi diventano niente più che un "complessa perdita di tempo".
La ragione dello sbocco occupazionale eventuale, da sola, non è sufficiente per rendere Java un "must" da
insegnare.
Python
(I.a soluzione)
(II.a soluzione)
import sys
a = input()
a = sys.stdin.readline()
b = input()
b = sys.stdin.readline()
c=a+b
c = int(a) + int(b)
print c
print c
%> python add.py
%> python add.py
Tempo di scrittura: circa 1 minuto , includendo il testing ed il debugging.
Concetti da spiegare: import, variables, sys.stdin, readline (reads a string), int (converts a string to an
integer), print.
Pro e Contro: Python ha molti aspetti positivi: impone un buon stile di programmazione (l'indentazione è
significativa); OO disponibili ma non vengono applicate, eccezioni usate ma non forzate; non è un
linguaggio diffuso in ambito universitario; molte applicazioni del mondo reale sono in Python; permette di
concentrarsi su algoritmi e problemi, non su caratteristiche del linguaggio e sulle sue lacune; è
multipiattaforma ed ha un potente set di librerie; è sicuro; ha un potente insieme interno di tipi di dati
(dizionari, liste, sequenze, funzioni, insiemi); ha un potente insieme di strutture di controllo; richiede meno
linee di codice per ogni dato problema, ed è più leggibile, in tal modo si acquisisce una maggiore
produttività. Per l'insegnamento come primo linguaggio potrebbe essere idoneo. Come si può vedere dagli
esempi precedenti (ignorando BASIC), Python richiede meno tempo, minor numero di linee di codice, e
minor numero di concetti. Inoltre, alcuni errori comuni degli studenti sono completamente aggirati in
Python, come: fine linea (senza punti, virgole dimenticate); nessuna dichiarazione di tipo; allocazione
dinamica della memoria e Garbage Collection.
Infine, la programmazione in Python è divertente! Divertimento e frequente gratificazione suscitano
crescente interesse nello studente spingendolo a imparare a programmare Python non è solo un
linguaggio di scripting, o ma è un completo linguaggio di livello molto alto ideale per molte applicazioni, tra
cui semplici funzioni di scripting. Infine essendo un linguaggio interpretato e per altre sue caratteristiche il
codice Python può essere molto più lento del codice C equivalente.
C++
Si potrebbe anche pensare al C++ come linguaggio per l'insegnamento dei concetti di programmazione
(alternativa valida, permettendo una programmazione sia di alto livello che di basso livello). Il programma
corrispondente in C++:
#include <iostream>
int main()
{
int a,b;
std::cin >> a >> b;
int c=a+b;
std::cout << c;
}
%> gcc add.cpp -lstdc++ -o add
%> ./add
Tempo di scrittura: circa 1 minuto , includendo il testing ed il debugging.
Concetti da spiegare: le direttive del preprocessore (#include), il concetto di funzione (main), ed il tipo del
risultato di ritorno della funzione main (return types); le eccezioni che il main può assumere: potrebbe non
esplicitare un valore di ritorno o restituire 0 ("return 0" ) alla fine della funzione, variabili, tipi (int);
streams, operatori di stream ("<<" e ">>") e cin/cout; compilazioni, parentesi (graffe) e terminatori (;) delle
istruzioni; espressioni (c=a+b).
Pro e Contro: C++ rappresenta un buon compromesso fra un linguaggio per gli esperti e un primo approccio
per i neofiti. Tuttavia ci sono molti concetti da spiegare prima che uno studente possa diventare autonomo
e scrivere una semplice espressione.
Smalltalk
x := FillInTheBlank request: 'Enter a number for X'.
y := FillInTheBlank request: 'Enter a number for Y'.
Transcript show : x + y.
Tempo di scrittura: circa due minuti.
Concetti da spiegare: assegnazione; nuova logica e più operatori utilizzati nella stessa riga.
Pro e Contro: la pulizia del linguaggio è piuttosto evidente come lo è la sinteticità.
Lisp
(print (+ (read) (read)))
Tempo di scrittura: circa 1 minuto.
Concetti da spiegare: il livello annidato delle parentesi; notazione inversa (operatori prima degli operandi);
nuova logica di composizione delle istruzioni
Pro e Contro: una volta compresa la logica è immediato, tuttavia eseguire il programma su un client diventa
troppo complicato.
Ruby
a = gets.to_i
b = gets.to_i
c=a+b
puts c
Stanganelli L., Gioco e programmazione
Lingu@ggi 21.0, n. I, anno 2010
Tempo di scrittura: circa 1 minuto, testing e debugging compreso.
Concetti da spiegare: variabili; istruzioni di IO: gets, puts; differenza fra integer e string.
Pro e Contro: molto simile a python; linguaggio orientato agli oggetti, meglio di Java e abbastanza facile da
spiegare; la complessità può variare da molto semplice, come sopra, o moderato, fino a diventare
complesso; Tutti i vantaggi indicati per Python sono validi per Ruby, tranne forse la funzione di blocco della
struttura.
Perl
#!/usr/bin/perl
print "enter a: ";
$a = <STDIN>;
print "enter b: ";
$b = <STDIN>;
print $a + $b . "\n";
#!/usr/bin/perl
print <STDIN> + <STDIN>;
Tempo di scrittura: circa 1 minuto, testing e debugging compreso.
Concetti da spiegare: #! ; $variabili; concetto; auto-conversione da stringa a numero; interpolazione e
concatenazione di stringhe; precedenza degli operatori e funzioni.
Pro e Contro: Perl ha la reputazione di essere un linguaggio disordinato per essere insegnato in un corso di
neofiti. I pro ed i contro sono sostanzialmente quelli di phyton e ruby, ma perl sembra essere migliore.
Shell
Un altro approccio interessante sarebbe quello di utilizzare una shell, nell’esempio di phyton supponendo
di scrivere le seguenti istruzioni dal prompt della shell:
riga per bash/sh/ksh/zsh:
read a; read b; echo $[a + b]
riga per awk:
awk 'BEGIN { getline a; getline b; print a + b; exit; }'
oppure:
awk '{ a = $0; getline b; print a + b; exit; }'
riga per perl:
perl -e 'print <> + <> . "\n"'
Naturalmente tutto potrebbe essere formattato in uno script file piuttosto che immesso da riga di
comando. Potrebbe essere più conveniente che scrivere un programma in C++ o java. Usare il giusto
strumento per il proprio lavoro costituisce sempre una buona lezione da imparare e spesso uno script shell
è la soluzione. Ovviamente non sempre possiamo usare script per risolvere i problemi: si pensi ad
applicazioni molto complesse. Non si trascuri che i programmatori unix spesso utilizzano shell e awk.
Sarebbe utile sapere come si scrivono le istruzioni rapide nella finestra di controllo del sistema operativo
anche se può sembrare inutile, ma in realtà è formativo e apre la mente dello studente.
Tempo di scrittura: circa 30 secondi, testing e debugging compreso.
Concetti da spiegare: shell; awk; scripting; esecuzione da finestra dei comando; fondamenti dei sistemi
operativi; linux, unix, windows (comandi elementari).
Pro e Contro: richiede molta esperienza e soprattutto un livello di comprensione e di focalizzazione del
problema. Certamente l'uso della programmazione shell è uno degli strumenti da insegnare agli studenti.
Pascal
var a,b,c:integer;
begin
readln(a,b);
c:=a+b;
writeln(c);
end.
Tempo di scrittura: circa 2 minuti, testing e debugging compreso.
Concetti da spiegare: variabili, tipi; blocchi e terminazione di linee e di blocchi; readln, writeln; visibilità
begin..end.
Pro e Contro: il Pascal è un linguaggio per la didattica molto chiaro e formativo, però è superato sebbene a
suo tempo era un enorme miglioramento rispetto al Basic. Pascal è molto meno espressivo di Python.
Inoltre Pascal si è evoluto in Delphi, ma questo è un linguaggio proprietario, e come tale non è conveniente
sceglierlo per l’insegnamento, dato che oggi si è più orientati verso l’open source.
Prolog
C is A+B
Tempo di scrittura: circa 10 secondi, compreso testing e debugging.
Concetti da spiegare: il parsing; variabili.
Pro e Contro: Prolog è il migliore linguaggio a livello concettuale.
In tabella 1 vengono riassunte le caratteristiche emerse durante la valutazione comparata dei linguaggi
operata in questo paragrafo. Si noti che, per ogni colonna sono state adoperate delle metriche lineari per
rappresentare l'attributo riportato in cima alla colonna così è più facile estrarre la riga relativa al linguaggio
più adeguato ai nostri scopi. In particolare la scala utilizzata è sempre a 5 valori (da 1 a 5) tranne per
l'attributo “contro e pro” per il quale essendo i due sotto attributi mutuamente esclusivi, per evidenziare il
prevalere dell'uno sull'altro si utilizza l'intervallo di valori [-2,2] zero compreso.
Linguaggio
Tempo
scrittura
[1-5]
Difficoltà
apprendimento
[1-5]
Concetti
da
spiegare [1-5]
Contro e
pro [-2..2]
Tipo
Basic
1
1
2
0
imperativo
C
3
3/4
3
-1
imperativo
Java
5
4
3/4
-2
imperativo
Python
1/2
1/2
2
+1
Imperativo/scripting
C++
1/2
3
3
-1
imperativo
Smalltalk
2
2
1/2
0
imperativo
Lisp
1/2
1/2
2
0
dichiarativo
Ruby
1/2
1/2
2
1
Imperativo/scripting
Perl
1/2
2
2
0
Imperativo/scripting
Shell
1
3
3
1
scripting
Pascal
2
2
2
-1
imperativo
Prolog
1
1
2
2
dichiarativo
note
Tab. 1: Quadro riassuntivo della valutazione comparata dei linguaggi per esprimere il concetto C=A+B
In realtà la programmazione e le attività di un gioco sono molto simili, perché entrambe le attività sono
costituite da una sequenza di azioni elementari eseguite allo scopo di raggiungere un determinato obiettivo
ed anche per il risvolto di gratificazione psicologica che la programmazione, al pari del gioco, fornisce.
Infatti, chi scrive un buon programma e lo vede funzionare è gratificato allo stesso modo con il quale si
sente soddisfatto dopo aver superato un livello di un gioco di abilità!
Il gioco e la programmazione sono processi così vicini fra di loro in quanto, come in tutte le attività di
apprendimento, l'obiettivo è riconducibile a due sotto-obiettivi fondamentali che bisogna aver raggiunto:
Stanganelli L., Gioco e programmazione
Lingu@ggi 21.0, n. I, anno 2010
a) essere in grado di risolvere problemi;
b) essere in grado di usare un linguaggio (diverso da quello naturale) per risolvere un problema, spesso
utilizzando un computer.
Ci sono 3 abilità in questo: sapere, saper fare, e saper far fare esposto dai due sotto-obiettivi citati. Tutte
queste attività (a e b) e le abilità che da queste derivano, se incanalate nella giusta direzione, possono
essere considerate come gioco, ma prima di fare delle proposte occupiamoci di analizzare per bene il
dominio del linguaggio.
Bisogna subito dire che il linguaggio di programmazione è solo uno strumento per esporre i concetti ed
in particolare quelli della programmazione, che quindi riguardano alcuni costrutti logici presenti nell'algebra
della logica delle proposizioni (congiunzione, disgiunzione, selezione, ripetizione, iterazione) ma spesso
poco esercitati anche nel linguaggio naturale (basti pensare a quanto poco si eserciti il linguaggio italiano e
le sue regole sintattiche in diverse scuole). L'uso del linguaggio di programmazione fra quelli noti (C, C++,
Java, solo per fare qualche nome) come base per l'insegnamento, ha mostrato che aumenta lo stato di
frustrazione fra gli studenti liceali e universitari in quanto: (I) gli studenti senza alcuna esperienza mostrano
subito molte difficoltà, (II) gli studenti con tanta esperienza lo troveranno molto noioso. Allora è molto
meglio dedicarsi a concetti fondamentali che sottendono alla programmazione piuttosto che ai linguaggi, e
sono tanti, che la sintetizzano. Infatti, l'equivoco più comune nel quale si incorre quando si apprende un
linguaggio di programmazione è quello di pensare che i concetti che si apprendono sono presenti solo in
quel linguaggio e non già il frutto di costrutti linguistici più generali e pertanto indipendenti dal linguaggio
di programmazione. È più utile privilegiare i concetti che non il modo di esprimerli assecondando
l'espressione alla estrema semplicità possibile così da interessare e facilitare lo studente a rappresentare
chiaramente la propria idea senza essere distratto dai dettagli. Allora introdurre i concetti astratti di
programmazione è il primo passo da compiere, anzi è meglio descriverli (privilegiando il cosa è) piuttosto
che spiegare i dettagli (come si fa). Insomma l’attività preliminare è insegnare agli studenti a pensare e a
interagire fra se stessi e la realtà che li circonda! Successivamente si può passare all'uso del computer e del
linguaggio per descrivere una soluzione.
Altro equivoco è quello di confondere la conoscenza di un linguaggio con la capacità di risolvere
problemi: sono due attività completamente diverse. Il possesso del "sapere" del primo non implica
necessariamente il secondo.
Le analogie tra gioco e programmazione sono evidenti per programmatori esperti che quindi conoscono
bene i linguaggi imperativi, invece per insegnare a un individuo che ignora il mondo della programmazione
è meglio orientarsi verso un linguaggio dichiarativo come si evince dalla tabella 1.
3. I linguaggi dichiarativi si avvicinano al gioco: un esempio
Esiste qualcosa di più semplice del Prolog? La risposta è sì, un linguaggio del tipo WYSIWYG (What you
see is what you get), tale tipo di linguaggio è LOGO. Esso si basa su semplici concetti (una tartaruga che si
muove) e semplici comandi (left, right, up e down). Sebbene i comandi siano semplici si possono realizzare
anche algoritmi molto complessi. L'insieme dei comandi costituisce un insieme funzionalmente completo:
con cui si possono costruire tutti i tipi di algoritmi. Siccome è molto semplice anche spiegare le primitive
dell'insieme dei comandi, si possono insegnare i concetti giocando, partendo da quelli più rudimentali e
fino ad arrivare a quelli più complessi. Insegnare ed imparare una ripetizione o una selezione con la tecnica
del WYSIWYG è veramente facile e divertente. Il vantaggio è che questi concetti non hanno bisogno di
essere spiegati o al più richiedono poco tempo per farlo, inoltre è un ambiente divertente nel quale
imparare giocando o giocare imparando! Come esempio più complesso, si riporta in figura 1 un solido di
rotazione disegnato con Logo e in figura 2 una finestra di Windows ottenuta con Logo
Fig. 1: Un solido di rotazione disegnato con LOGO
Fig. 2: Una finestra di windows disegnata con LOGO
proprio per mostrare che con Logo si possono effettuare anche algoritmi complessi, come si può anche
simulare l'uso di un altro linguaggio (ad esempio Pascal o Basic), quindi è un linguaggio molto potente.
Appare evidente che non essendovi richiesta di mercato di un linguaggio di questo tipo non ci sia al pari
un’esigenza di diffonderlo ed insegnarlo, tuttavia è un linguaggio estremamente potente e versatile, si
utilizza per applicazioni nel campo della robotica e non solo, ed ha l'enorme vantaggio di essere semplice
ed efficace per l'insegnamento alle giovani generazioni le quali dovendo imparare più di un linguaggio
potrebbero per esempio cominciare proprio da questo.
Prolog è un linguaggio dichiarativo che descrive cosa fa un programma ma non come lo fa al contrario
dei linguaggi di programmazione tradizionali. Più semplice da imparare per chi non ha la forma mentis del
programmatore (è meglio scrivere su un foglio bianco piuttosto che su uno dove ci sono già informazioni,
ossia è più semplice insegnare il Prolog a chi non possieda i concetti di programmazione piuttosto che a un
programmatore Java!). Deriva dal LISP (List Processor) altro linguaggio di programmazione. I linguaggi di
programmazione procedurali quali Cobol, Pascal, Fortran ed altri oltre ad essere per la maggior parte
desueti (anche se esistono ancora i legacy system come quelli bancari scritti in Cobol) poco si prestano a
presentare la programmazione come qualcosa di ludico e soprattutto di semplice.
Java e gli altri linguaggi ad oggetti potrebbero essere visti come linguaggi per apprendere linguaggi? Java
potrebbe essere un metalinguaggio?
Si parla tanto della semplicità di Java e spesso viene usato per realizzare giochi però non è stata fatta
ancora nessuna sperimentazione per capire se è veramente semplice da apprendere!
In definitiva per apprendere linguaggi procedurali e ad oggetti sembra ci voglia qualcosa di più che
semplici nozioni ma un vero percorso formativo, certo è che ancora nessuno ha appreso i “misteri” di
questi linguaggi giocando!
Per tutti questi motivi ho scelto Prolog (Programming in logic), che come detto essendo molto vicino al
modo di pensare dell’essere umano risulta più comprensivo ed ancora è stato usato anche per realizzare
giochi come ad esempio quello degli scacchi (Eigen, Winkler 1986).
Ora vediamo un semplice esempio di funzionamento di tale linguaggio.
Stanganelli L., Gioco e programmazione
Lingu@ggi 21.0, n. I, anno 2010
Scriviamo un programma Prolog che simuli l’imbarco delle carrozze di un treno su di un traghetto per
superare lo Stretto di Messina. Il programma deve dare la possibilità di effettuare le seguenti operazioni
mediante opportuni predicati:
- inserimento di una o più carrozze;
- estrazione di una o più carrozze;
- ricerca della carrozza più vecchia;
- calcolo del numero medio di posti a sedere.
Le informazioni relative alla singola carrozza sono:
- un codice seriale;
- il numero di posti a sedere;
- l’anno di costruzione.
Si consideri il traghetto come una pila, nella quale le carrozze entrano ed escono dallo stesso varco,
quindi la politica di inserimento ed estrazione delle carrozze è LIFO (last in first out).
La carrozza (elemento principale di questo problema) viene rappresentata con un fatto prolog del tipo:
carrozza(Cod ,Posti, Anno)
dove Cod indica il codice identificativo della carrozza, Posti indica il numero di posti presenti sulla
carrozza e Anno indica l’anno di costruzione della stessa.
L’esplicita richiesta di trattare il traghetto come una pila prevede che l’imbarco delle nuove carrozze
(inserimento dell’elemento nella pila – push) e lo sbarco delle stesse (estrazione dalla pila – pop) devono
essere effettuati sempre dalla testa della lista di carrozze.
Di seguito si mostrano le soluzioni dei quattro punti suddetti.
L’operazione di inserimento di una o più carrozze viene effettuata dal predicato:
push(Lista1, Lista2, Lista3)
Questa operazione permette di inserire gli elementi della Lista1 in testa alla Lista2. Lista3, conterrà il
risultato della chiamata push.
L’operazione di estrazione di una o più carrozze viene effettuata dal predicato:
pop(N, Lista1, Lista2)
Questa operazione permette di estrarre N elementi dalla testa della pila Lista1. Lista2, conterrà il
risultato della chiamata pop, cioè la lista di carrozze estratte da Lista1.
L’operazione che ricerca la carrozza con l’anno di costruzione più vecchio è eseguita dal predicato:
search(Lista, CarrVecchia)
Questa operazione effettua la scansione di tutta la Lista confrontando gli anni di costruzione di ogni
elemento carrozza(Cod ,Posti, Anno) e scrivendo nella variabile di uscita CarrVecchia quella con l’anno di
costruzione più piccolo.
L’operazione che calcola il numero medio di posti a sedere tra le carrozze del traghetto è:
seats_average(Lista,Media)
Questa operazione effettua la divisione tra il numero dato dalla somma di tutti i posti di tutte le carrozze
e il numero di carrozze presenti nell’argomento Lista. Il risultato è restituito nella variabile Media.
Ogni predicato suddetto viene realizzato tramite istruzioni prolog che implementano le liste e la
ricorsione (che sono i concetti fondamentali di prolog).
Come è possibile osservare si possono utilizzare istruzioni che sono comprensibili dall’essere umano ma
anche dalla macchina.
4. Conclusioni
Qualcuno ha detto "se tutto quello che hai è un martello allora ogni problema ti sembrerà un chiodo". E'
evidente che l'obiettivo di uno studente è quello di ampliare il repertorio di strumenti a disposizione per
costruire programmi di qualità e che quindi ha bisogno di conoscere più linguaggi durante la sua vita, ma da
dove cominciare? Ovviamente a partire dal martello e cioè da un linguaggio semplice. Una soluzione
potrebbe essere quella di orientarsi verso un linguaggio imperativo (C, Java, C++) oppure verso un
linguaggio di scripting oppure un linguaggio dichiarativo. La prima scelta, quella più alla moda, è sui
linguaggi imperativi. Questi sono importanti per insegnare concetti e per le prospettive che essi danno dal
punto di vista dell'impiego e delle classi di problemi da risolvere ma otteniamo solo complicazione in
termini di concetti da insegnare e di tempo speso per farlo, inoltre gli studenti devono mostrare un
profondo radicamento nella conoscenza del linguaggio prima di poter scrivere qualcosa senza errori e i
concetti da esporre per insegnare/apprendere il linguaggio costituiscono un sovraccarico sia per il docente
che per lo studente. La seconda scelta, meno frequente, potrebbe essere un linguaggio di scripting anzi
questi costituiscono un "must" oggi da insegnare ma non a studenti alle prime armi nella programmazione
in quanto non sono buoni linguaggi dal punto di vista della "pulizia" delle strutture logiche. La migliore
scelta è utilizzare un linguaggio dichiarativo anziché imperativo, in quanto conserviamo lo stesso livello di
astrazione del modo in cui pensiamo il concetto: la somma in questo caso ed impariamo giocando. La stessa
cosa varrà per le altre strutture logico-linguistiche (se, se-allora-altrimenti, alternativa etc.) che
rappresentano un primo set di strutture utili alla costruzione dei programmi. Questa scelta è quella più
appropriata sia per la semplicità che per la conservazione dell'astrazione del concetto al livello al quale si
trova. Un linguaggio che preservi l'astrazione concettuale, è il Prolog. Esso consente di risolvere problemi
molto agevolmente ed è realmente uno strumento potente per la risoluzione dei problemi. Gli studenti
sono inizialmente molto diffidenti perché hanno il culto della complessità anche nei linguaggi: anni ed anni
di insegnamenti in questo senso hanno fatto il danno! Quando inizialmente gli si dice: ”dovete pensare in
maniera semplice” spesso chiedono: perché? Da subito non ritengono che la semplicità è una virtù, anzi
pensano che il modo più facile per sentirsi superiori è quello di fingere di capire ciò che gli altri non sono in
grado di capire. Ma la questione si chiarisce subito appena si mettono all’opera (il gioco) perché capiscono
ben presto che si originano fra loro due tipologie di gruppi: i doers (De Bono 1998) ed i describers. I primi, i
doers, hanno la necessità di agire e quindi amano la semplicità che vuol dire anche efficienza. I secondi, i
describers, hanno orrore della semplicità sembra sentirli esclamare “una cosa che può essere capita da tutti
come può essere seria?”. Tuttavia anche questi ultimi dovendosi scontrare realmente con i problemi
capiscono che sono sulla cattiva strada.
Si è visto nei paragrafi precedenti come è possibile imparare nozioni di programmazione (il concetto di
pila, di operazione di inserimento ed estrazione dalla pila, i concetti di lista, il concetto di insieme numerale
di posti in una carrozza, etc.) mediante un semplice esercizio che simuli l’imbarco di un treno su un
traghetto, tutto ciò può essere visto come un gioco di abilità ed i concetti che si apprendono in questo
modo non si dimenticano facilmente. In modo analogo è possibile risolvere molti problemi reali e problemi
dell’intelligenza artificiale. Particolarmente adatto per quest’ultimo scopo in quanto le caratteristiche di
Prolog sono: non determinismo; capacità di elaborazione simbolica; pattern matching; uniformità di
programmi e dati; rappresentazione della conoscenza e ragionamento; uso interattivo del linguaggio
(interpretato); rapid prototyping.
Bibliografia
- libri e monografie:
Clocksin W.F., Mellish C.S., Programming in Prolog, Springer, New York, 2003.
De Bono E., Creatività e pensiero laterale, Rizzoli editore, Milano, 1998.
Eigen M., Winkler R., Il Gioco:le leggi naturali che governano il caso,Adelphi, Milano, 1986.
Hofstadter D.R. , Dennet D.C., L’ IO della mente, Adelphi, Milano, 1985.
Maciaszek L.A., Sviluppo di sistemi informative con UML, Addison-Wesley, 2002.
Maresca P., “Apprendimento personalizzabile in un ambiente collaborativo per la didattica universitaria
di primo livello” , Atti del convegno Didamatica 2001, Bari, 3-5 Maggio 2001, pp. 284-292.
Nilsson N.J., Intelligenza Artificiale, Apogeo, Milano, 1998.
Pressman R.S., Principi di Ingegneria del Software, Mc Graw Hill, 1999.
Russel B., I Principi della Matematica, Longanesi & C, Milano, 1980.
Trentin G.,Dalla formazione a distanza all’apprendimento in rete, Franco Angeli, Milano, 2001.
Sitografia
Dienneti: http://www.dienneti.it/, ultima consultazione: 30.06.2010
Stanganelli L., Gioco e programmazione
Lingu@ggi 21.0, n. I, anno 2010
English-4kids: http://www.english-4kids.com/, ultima consultazione: 30.06.2010
Funbrain: http://www.funbrain.com/, ultima consultazione: 30.06.2010
Fact Monster: http://www.factmonster.com/, ultima consultazione: 30.06.2010
Logo: http://el.media.mit.edu/logo-foundation/, ultima consultazione: 30.06.2010