Lisp sempreverde

Il linguaggio Lisp è stato creato nel lontano 1959 da John McCarthy presso il Massachusetts Institute of Technology per i computer della serie IBM 700/7000 e per applicazioni di intelligenza artificiale.
E’ nato come linguaggio funzionale ed è il più antico linguaggio di questo tipo. Ma dal 1959 ad oggi è passato attraverso varie evoluzioni e sono stati creati numerosi suoi dialetti, al punto che le varie versioni che sono oggi disponibili non si possono catalogare come linguaggi funzionali puri.
Tra queste varie versioni, che vanno dal Common Lisp all’AutoLISP (utilizzato in AutoCAD), dallo Scheme all’Emacs Lisp, ne segnalo una che ritengo notevole per la semplicità di uso e per la ricchezza di funzioni preconfezionate che offre: newlisp.
Sul sito www.newlisp.org troviamo tutto ciò che lo riguarda: documentazione e possibilità di download. Il tutto all’insegna del software libero.
Creato nel 1991 per Windows fu convertito per Linux nel 1999 e, di rilascio in rilascio, si è sempre più arricchito: il 20 gennaio 2015 è stata rilasciata la versione 10.6.2, disponibile per Linux, Windows e OS X.
Lo ritengo un formidabile linguaggio di scripting per studenti e matematici.
Una volta che ci si è abituati all’uso delle numerose parentesi e alla notazione prefissa tipiche del Lisp diventa anche rapido e divertente.

Utili funzioni preconfezionate sono le seguenti.
Calcolo matriciale:
invert ritorna l’inversione di una matrice
det calcola il determinante di una matrice
multiply moltiplica due matrici
mat applica un operatore aritmetico a due matrici o a una matrice e a un numero
transpose ritorna la trasposta di una matrice
Calcoli statistici:
beta calcola la funzione beta
betai calcola la funzione beta incompleta
binomial calcola la funzione binomiale
corr calcola il coefficiente di correlazione di Pearson
crit-chi2 calcola il valore del Chi quadrato di Pearson per una data probabilità
crit-f calcola il valore critico minimo del test F di Snedecor per una data probabilità
crit-t calcola il valore critico minimo del test t di Student per un dato livello di confidenza
crit-z calcola il valore critico normale di un test Z di Fisher per una data probabilità cumulata
erf calcola la funzione di errore per un numero
gammai calcola la funzione gamma incompleta
gammaln calcola la logaritmica della funzione gamma
kmeans-query calcola la distanza euclidea tra un vettore e un centroide
kmeans-train applica la cluster analysis a una matrice
normal genera una lista di numeri casuali normalmente distribuiti data una media e uno scarto quadratico medio
prob-chi2 calcola la probabilità cumulata del test Chi quadrato di Pearson
prob-f calcola la probabilità di un valore riscontrato del test F di Snedecor
prob-t calcola la probabilità di un valore riscontrato del test T di Student
prob-z calcola la probabilità cumulata di un valore riscontrato del test Z di Fisher
stats calcola valori statistici (media, varianza, scarto quadratico medio, ecc.) di una serie di numeri
t-test utilizza il test t di Student per valutare la differenza tra medie
Calcoli finanziari:
fv calcola il valore futuro di un investimento
irr calcola il tasso di rendimento interno
nper calcola il numero di periodi per un investimento
npv calcola il valore attuale di un investimento
pmt calcola la rata costante per estinguere un prestito
pv calcola il valore attuale di una rendita
Ovviamente quelle che ho richiamato sono comprese nella lunghissima serie di funzioni che ci offre newlisp e le ho richiamate in quanto sono difficilmente presenti in altre versioni del linguaggio Lisp.
La lista completa e la sintassi richiesta per tutte le funzioni la troviamo in http://www.newlisp.org/downloads/manual_frame.html.

Altra cosa utile e sfiziosa che ci regala newlisp è la possibilità di creare ed eseguire programmi con interfaccia grafica (GUI), grazie all’aggiunta a newlisp, attorno al 2008, di un server per interfaccia grafica costituito dai file guiserver.jar (per far funzionare il quale occorre aver installato la macchina virtuale java sul computer) e dalla sua interfaccia guiserver.lsp.
La sintassi per programmare con GUI la troviamo all’indirizzo http://www.newlisp.org/guiserver-jp/.
Un piccolo esempio di programma con interfaccia grafica è scaricabile qui.
Un esempio un tantino meno banale lo troviamo invece qui: questo programma è utile per determinare i codici da inserire nella programmazione con GUI per creare i colori desiderati.
Ricordo a chi usa Linux che i file eventualmente scaricati vanno resi eseguibili per provarli.

Buon divertimento con newlisp.

Insidie nei programmi di calcolo

Nel mio articolo sul Software libero per calcolare ho accennato alla delicatezza del software di calcolo ed all’esistenza di alcune trappole annidate nei vari linguaggi di programmazione, con il pericolo che il programma che utilizziamo per fare un calcolo fornisca un risultato sbagliato senza che ce ne accorgiamo.
Al fine di mettere in guardia il programmatore dilettante che voglia cimentarsi nel costruire qualche strumento di calcolo a suo uso e consumo per calcolare, ad esempio, la temperatura percepita nota la temperatura e l’umidità relativa (o altre cose che non troviamo facilmente in programmi già predisposti), ho pensato di indicare in questo articolo quali sono le due principali fonti di complicazione: la questione del separatore decimale e quella della divisione tra interi.

Il separatore decimale

In tutti i linguaggi di programmazione il separatore decimale è il punto (.) ed è questo che deve essere rigorosamente usato nelle assegnazioni interne ai programmi.
Il problema si pone, specialmente per noi italiani abituati ad usare come separatore decimale la virgola, quando è richiesto un input numerico all’utente, in quanto egli, anche se avvisato sul separatore decimale da utilizzare, può sbagliare e ciò può avere, in certi casi, conseguenze disastrose sul risultato dell’elaborazione compiuta dal programma.
I linguaggi più sicuri da questo punto di vista sono Ada, Java, Pascal e Python in quanto in questi linguaggi è imposto un input con separatore decimale punto e, se l’utente usa la virgola, viene elevata una eccezione di input e non viene fornito alcun risultato. Attraverso una opportuna gestione di questa eccezione è possibile avvisare l’utente dell’errore ed invitarlo a formulare un input corretto: il tutto senza uscire dal programma. Se l’eccezione non viene gestita il programma termina senza risultato e il danno è circoscritto a questo.
I linguaggi più subdoli sono il C, il C++ e PHP in quanto impongono il punto ma, se l’utente usa la virgola, non sollevano eccezioni di input, ignorano ciò che viene immesso dopo la virgola e forniscono risultati sballati: il tutto senza che l’utente sappia alcunché, né sull’errore compiuto usando la virgola in luogo del punto né – il che è gravissimo – sul fatto che il risultato che gli è stato fornito dal programma è sbagliato. Unico rimedio a tutto ciò è un accurato controllo dell’input, carattere per carattere, in modo da rimediare alla falla del linguaggio con accorgimenti di programmazione che sollevino un’eccezione gestibile nel momento in cui nell’input venisse trovata una virgola. Eccezione gestibile fino a sostituire un punto alla virgola, nel caso la si trovasse, senza dire nulla all’utente, ed arrivare comunque ad un risultato corretto: in questo modo possiamo avere un programma per il quale va bene l’uso di entrambi i separatori decimali, punto e virgola.
Vi sono, infine, i linguaggi del gruppo Visual Studio di Microsoft, dove i problemi non mancano, anzi…..
Visual C++ di Visual Studio si comporta esattamente come il normale C++.
Visual C# di Visual Studio ha la particolarità che, quando viene caricato su un computer, si adegua alla cultura dell’utente: se il sistema operativo installato è una versione italiana, anche Visual C# sarà italiano. Tra le caratteristiche di questa cultura c’è il fatto che l’utente usa come separatore decimale la virgola e C# si adegua: al suo interno usa rigorosamente il punto come separatore decimale ma quando legge un input dell’utente italiano si aspetta di trovare, come separatore decimale, la virgola. Se l’utente usa il punto, questo viene semplicemente ignorato e il numero viene letto come un intero composto da tutte le cifre immesse, sia quelle prima che quelle dopo il punto e l’elaborazione prosegue con questo numero, con tutte le disastrose conseguenze del caso.
Visual Basic, sia nella vecchia versione, sia in quella più aggiornata, è il massimo della confusione. Anch’esso, al momento dell’installazione, si adegua alla cultura dell’utente ma lo fa parzialmente: mentre, infatti, la funzione Cdbl() per convertire in numero la stringa immessa dall’utente si adegua alla cultura di questi e, se egli usa un sistema operativo in italiano, si aspetta di trovare la virgola come separatore decimale e, se trova il punto, fa avvenire esattamente quello che avviene in C#, la funzione Val(), utilizzabile per lo stesso scopo, si aspetta di trovare comunque il punto come separatore decimale e, se trova una virgola, non legge oltre ed incamera un numero intero composto dalle sole cifre immesse dall’utente prima della virgola e prosegue così il suo percorso di elaborazione. Visual Basic, pertanto, non è solo subdolo ma è anche ambiguo.
Fortunatamente le versioni di Visual C# e di Visual Basic delle più recenti edizioni di Visual Studio hanno la funzione membro Replace() dell’oggetto stringa che, con poca spesa, ci aiuta a correggere l’input in modo da poter accettare invariabilmente sia il punto che la virgola dall’utente (sempre, in Visual Basic, stando attenti alla correzione da apportare in coerenza a che cosa si usa per convertire la stringa).

Divisione tra interi

L’uso dell’operatore / tra due numeri fornisce come risultato il quoziente di una divisione.
Questo risultato è il quoziente vero, qualunque sia il tipo di numero indicato prima e dopo l’operatore /, solo nei linguaggi Pascal, Python 3 e Visual Basic (sia nella vecchia che nella nuova versione). Per quoziente vero si intende il 2,5 che risulta da 5 / 2.
Nei linguaggi C, C++ e C# se i numeri indicati prima e dopo l’operatore / sono interi si ha una divisione tra interi che fornisce come risultato la parte intera del quoziente. Cioè 5 / 2 fornisce il risultato 2. Purtroppo ciò avviene anche quando la variabile cui assegnare il risultato sia stata dichiarata come double, senza che vi sia alcuna segnalazione di errore. Per ottenere il quoziente vero occorre che almeno uno dei due numeri inseriti prima e dopo l’operatore / sia un double (basta scrivere 5.0 anziché 5).
In Java questo inconveniente si presenta soltanto se l’espressione di divisione è inserita in una istruzione di stampa, senza passare attraverso l’assegnazione a variabili. L’istruzione System.out.println(5/2) stampa 2 e, per ottenere la stampa del risultato corretto occorre scrivere System.out.println(5/2.0) o System.out.println(5.0/2). Non è invece possibile, per sollevamento di eccezione nella compilazione, assegnare il risultato di 5/2 ad una variabile dichiarata double, il che, almeno in parte, attutisce i pericoli che Java ha ereditato dal C.
Allo stesso modo di Java si comporta Ada con la sola eccezione che la divisione inserita in una istruzione di stampa, perchè dia il risultato corretto deve avere sia prima che dopo l’operatore / un float. Cioè non basta dire Put(5.0/2) o Put(5/2.0) ma occorre dire Put(5.0/2.0): in caso contrario viene segnalato errore nella compilazione.
Python 2 è nella stessa situazione di Java se l’input è acquistito con la funzione raw_input(), in quanto tutto si sistema se con la conversione della stringa acquisita si memorizza il valore in una variabile float. Se l’input è acquisito con la funzione input(), dal momento che questa, in Python 2, ritorna un valore numerico, occorre che almeno uno dei due numeri sia scritto come float dalla tastiera.