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