Configura scite per lavorare con newLisp

9 08 2009

google_translate.gif
Translate To English!

newLisp è un linguaggio cross-platform, e trovare un ottimo editor, flessibile e relativamente semplice da usare, che sia pure esso stesso cross-platform non è stata una cosa facile. Alcuni editor sono fantastici ma non sono cross-platform, altri sono un pò “duri” da gestire (comandi solo da tastiera, linguaggi di scripting per macro e plugin proprietari, etc…), altri ancora sono fantastici ma avete bisogno di MOLTO tempo per imparare a gestirli a dovere. Dopo varie ricerche ho scelto Scite, un ottimo cross platform editor (anche se c’è da fare un pò di fine-tuning per quanto riguarda le configurazioni interne).
Sono stato ancora più felice quando ho scoperto che Kazimir, nel suo blog, aveva pubblicato un file per fare syntax highlight e quant’altro in Scite! L’ho quindi subito scaricato e mi sono messo al lavoro per personalizzare il mio Scite editor, creando il mio ambiente di lavoro “perfetto” (il file “properties” originale di Kazimir lo potete trovate a questo indirizzo: http://kazimirmajorinc.blogspot.com/2008/06/lispproperties-for-scite.html).
Studiando un pò mi sono poi accorto che Scite permette di scrivere delle macro in LUA (non in newLisp purtroppo :-)  ). Questo permette di raggiungere ottimi livelli di personalizzazione dell’editor. In questo articolo pubblicherò il mio file properties di Scite. Ogni volta che apporterò modifiche/aggiornamenti su tale file, o creerò scripts/plugins, li pubblicherò qui, con la categoria:  Scite Editor. Partendo quindi dal file properties generato da Kazimir, l’ho modificato ed esteso un pò.

NOTA: non fermatevi a vedere solo il codice sorgente! Alla fine del listato, ho scritto dei commenti in merito alle varie proprietà, così che voi stessi potrete voi stessi personalizzare il file per le vostre esigenze!
NOTA 2: ho creato il file su Scite per Linux, ed ho notato delle piccole differenze su quello Windows (per esempio, il background non è nero). Io non ho però nessun PC con Windows, sto quindi lavorando per fare dei tests su tale sistema operativo, facendo poi le modifiche necessarie (che pubblicherò puntualmente!).

CODICE SORGENTE DEL FILE “LISP.PROPERTIES”

# Define SciTE settings for Newlisp files.
view.whitespace=0
whitespace.fore=#333333
split.vertical=0
strip.trailing.spaces=1
strip.trailing.tabs=1
reload.preserves.undo=1

# Indentation
use.tabs=1
tab.size=4
tab.indent=1
backspace.unindents=1
indent.opening=1
indent.closing=1
indent.size=4
indent.auto=1
indent.automatic=1
view.indentation.guides = 1
view.indentation.examine = 3
highlight.indentation.guides = 1

# Editor starting position and size.
position.left=10
position.top=10
position.width=600
position.height=400

# Right edge
edge.column=80
edge.mode=1
edge.colour=#AAAAAA

# Sizes and visibility in edit pane
line.margin.visible=1
line.margin.width=4
margin.width=14
fold.margin.width=14
fold.margin.colour=#007F00
fold.margin.highlight.colour=#007F00

# caret
caret.fore=#FF0000
caret.width=3
caret.period=500

selection.back=#FF0000

file.patterns.lisp=*.lsp;*.lisp
filter.lisp=LISP (lsp lisp)|$(file.patterns.lisp)|

lexer.$(file.patterns.lisp)=lisp

# Lisp build in functions
keywords.$(file.patterns.lisp)= $ \
$ ! != $ $0 $1 $10 $11 $12 $13 $14 $15 $2 $3 $4 $5 $6 $7 $8 $9 \
$args $idx $it $main-args % & * + - / : < << <= = > >= >> ? @ \
class MAIN NaN? Tree abort abs acos acosh add address amb and \
append append-file apply args array array-list array? asin asinh \
assoc atan atan2 atanh atom? base64-dec base64-enc bayes-query \
bayes-train begin beta betai bind binomial bits callback case \
catch ceil change-dir char chop clean close command-event cond \
cons constant context context? copy copy-file cos cosh count \
cpymem crc32 crit-chi2 crit-z current-line curry date date-value \
debug dec def-new default define define-macro delete delete-file \
delete-url destroy det device difference directory directory? div \
do-until do-while doargs dolist dostring dotimes dotree dump dup \
empty? encrypt ends-with env erf error-event error-number error-text \
eval eval-string exec exists exit exp expand explode factor fft \
file-info file? filter find find-all first flat float float? floor \
flt for for-all format fv gammai gammaln gcd get-char get-float \
get-int get-long get-string get-url global global? if if-not ifft \
import inc index int integer integer? intersect invert irr join \
lambda? last legal? length let letex letn list list? load local \
log lookup lower-case macro? main-args make-dir map mat match max \
member min mod mul multiply name net-accept net-close net-connect \
net-error net-eval net-interface net-listen net-local net-lookup \
net-peek net-peer net-receive net-receive-from net-receive-udp \
net-select net-send net-send-to net-send-udp net-service net-sessions \
new nil nil? normal not now nper npv nth null? number? open or \
ostype pack parse pipe pmt pop pop-assoc post-url pow pretty-print \
primitive? print println prob-chi2 prob-z process prompt-event \
protected? push put-url pv quote quote? rand random randomize \
read-buffer read-char read-expr read-file read-key read-line \
real-path ref ref-all regex regex-comp remove-dir rename-file \
replace reset rest reverse rotate round save search seed seek \
select semaphore sequence series set set-locale set-ref set-ref-all \
setf setq sgn share signal silent sin sinh sleep slice sort source \
spawn sqrt starts-with string string? sub swap sym symbol? symbols \
sync sys-error sys-info tan tanh throw throw-error time time-of-day \
timer title-case trace trace-highlight transpose trim true true? \
unify unique unless unpack until upper-case uuid when while \
write-buffer write-char write-file write-line xml-error xml-parse \
xml-type-tags zero? | ~ \

word.chars.lisp=$(chars.alpha)$(chars.numeric)_-<>.#+@$%^&=*!?`§
word.characters.$(file.patterns.lisp)=$(word.chars.lisp)

comment.block.lisp=;
comment.box.start.lisp=;
comment.box.middle.lisp=;
comment.box.end.lisp=;
comment.stream.start.lisp=;111
comment.stream.end.lisp=;222

# White space
style.lisp.0=fore:#00FF00,back:#000000,size:10

# Line Comment
style.lisp.1=fore:#FFFF66,back:#000000,size:10

# Number
style.lisp.2=fore:#7F7FFF,back:#000000,size:10

# Keyword
style.lisp.3=fore:#FFCF00,back:#000000,size:10

# Unknown
style.lisp.4=back:#FFFFFF

# Quoted identifier
style.lisp.5=fore:#00FF00,back:#333344

# String
style.lisp.6=fore:#7FFFFF,back:#000000

# End of line where string is not closed
style.lisp.7=back:#FFFFFF,back:#000000

# Unknown
style.lisp.8=back:#FFFFFF,back:#000000

# Identifiers
style.lisp.9=fore:#00FF00,back:#000000

# Operators
style.lisp.10=fore:#FF7FFF,back:#000000

# -- syntax
style.lisp.11=back:#FFFFFF

# Undefined or unknown styles
style.lisp.12=back:#00FF00
style.lisp.13=back:#FFFF00
style.lisp.14=back:#FFFF00
style.lisp.15=back:#FFFF00
style.lisp.16=back:#FFFF00
style.lisp.17=back:#FFFF00
style.lisp.18=back:#FFFF00
style.lisp.19=back:#FFFF00
style.lisp.20=back:#FFFF00
style.lisp.21=back:#FFFF00
style.lisp.22=back:#FFFF00
style.lisp.23=back:#FFFF00
style.lisp.24=back:#FFFF00
style.lisp.25=back:#FFFF00
style.lisp.26=back:#FFFF00
style.lisp.27=back:#FFFF00
style.lisp.28=back:#FFFF00
style.lisp.29=back:#FFFF00
style.lisp.30=back:#FFFF00
style.lisp.31=back:#FFFF00

# Default selected text COLORS.
selection.back=#FFFFFF
selection.alpha=80

# Monospace per default
font.base=font:Courier,size:10
font.small=font:Courier,size:10
font.comment=font:Courier,size:10
font.code.comment.box=$(font.comment)
font.code.comment.line=$(font.comment)
font.code.comment.doc=$(font.comment)
font.text=font:times,size:10
font.text.comment=font:Courier,size:10
font.embedded.base=font:Courier,size:10
font.embedded.comment=font:Courier,size:10
font.monospace=font:Courier,size:10
font.vbs=font:Courier,size:10

# Code completion
autocompleteword.automatic=1
autocomplete.choose.single=0
lexer.$(file.patterns.flash)=lisp
autocomplete.flash.ignorecase=1

# Default
style.lisp.32=fore:#FF0000,back:#000000,size:10

# Line number
style.lisp.33=back:#00FF00,fore:#000000,size:10

# Brace highlight
style.lisp.34=back:#007f00,fore:#FFFF00,size:10

# Brace incomplete highlight
style.lisp.35=back:#7f0000,fore:#FFFF00,size:10

# Control characters
style.lisp.36=back:#000000;fore:#FF00FF,size:10

# Indentation guides
style.lisp.37=fore:#A00000,back:#000000,size:10

# Braces are only matched in operator style
# braces.lisp.style=10

# TOOLS
command.go.$(file.patterns.lisp)=cmd /K "newlisp -c -s 400000 $(FilePath)"
command.go.subsystem.$(file.patterns.lisp)=2

command.name.0.$(file.patterns.lisp)=Go (Output Box)
command.0.$(file.patterns.lisp)=cmd /K "newlisp -c $(FilePath)"
command.subsystem.0.$(file.patterns.lisp)=0

command.name.1.$(file.patterns.lisp)=Newlisp REPL (Command Window)
command.1.$(file.patterns.lisp)=cmd /K "newlisp"
command.subsystem.1.$(file.patterns.lisp)=2

command.name.2.$(file.patterns.lisp)=Newlisp REPL (Output)
command.2.$(file.patterns.lisp)=cmd /K "newlisp"
command.subsystem.2.$(file.patterns.lisp)=0

command.help.$(file.patterns.lisp)="C:/Program Files (x86)/newlisp/manual_frame.html"
command.help.subsystem.$(file.patterns.lisp)=2

Cosa da, e soprattutto: come si usa?!

  1. Scaricate Scite dalla sua home page (trovate il link anche nell’apposita sezione di questo blog).
  2. Aprite il file lisp.properties. Nota per gli utenti Linux: il file non può essere modificato come utente normale, quindi entrate in modalità root con il comando “sudo”, oppure con il comando “su”.
  3. Fate un backup del “vecchio” file lisp.properties (quello che andremo a sostituire).
  4. Sostituite il file appena aperto con quello che ho pubblicato.
  5. Salvate il tutto. Chiudete Scite e riaprite. Poi…
  6. … poi aprite un file newLisp (estensione “.lsp”).

Ecco come si presenta Scite con il file newLisp aperto: newlisp final Questo file “properties” permette di avere, in Scite, le seguenti funzionalità:

  1. Highlight della sintassi.
  2. Highlight delle parentesi tonde.
  3. Highlight dell’indentazione.
  4. Code completion (CARLO-ENTER).
  5. Eliminazione (pulizia) degli spazi e TABE in eccesso sulla riga (quelli oltre l’ultimo carattere scritto).
  6. Indentazione automatica.
  7. Possibilità di personalizzare la posizione iniziale e la dimensione dell’editor allo start-up.
  8. Posizionamento del “right edge” (linea sottile che mostra il bordo destro dell’editor – default al carattere 80). Possibilità di personalizzare il suo colore.
  9. Possibilità di personalizzare i colori del cursore e la sua frequenza di lampeggio.
  10. Per default, viene impostato il carattere di tipo MONOSPACE.

Rispetto alle impostazioni di Kazimir, ho modificato alcune combinazioni di colori e fonts. Sono scelte molto personali, quindi fate la vostra!

Una breve spiegazione sul file

Vorrei mettere in evidenza alcune parti del file, così che voi potrete personalizzarlo a vostro piacere.

view.whitespace=0
Serve per poter mostrare dei piccoli puntini al posto degli spazi (potete così mettere “in evidenza” gli spazi).

strip.trailing.spaces=1
strip.trailing.tabs=1
Configura Scite per eliminare SPAZI e TABS alla fine di ogni riga. Per esempio: <Questa è una riga di esempio                    > Gli spazi alla fine della riga verranno eliminati.

use.tabs=1
tab.size=4
tab.indent=1
Questi parametri indicano che il TAB può indentare il codice. Ogni TAB include 4 caratteri di indentazione.

backspace.unindents=1
Il tasto BACKSPACE permetterà di eliminare un livello di indentazione del codice.

indent.size=4
indent.auto=1
indent.automatic=1
Dettagli sull’indentazione stessa. E’ automatica (quindi ad ogni pressione del tasto ENTER il cursore si posiziona al livello di indentazione corretto rispetto al precedente, e non all’inizio della riga).

view.indentation.guides = 1
view.indentation.examine = 3
highlight.indentation.guides = 1
Mostrano le linee guida di indentazione.

# Editor starting position and size.
position.left=100
position.top=30
position.width=600
position.height=400
Autoesplicativo!  Posizione e dimensioni iniziali dell’editor. Suggerimento: questo codice, se volete che venga eseguito ogni volta che si apre l’editor (e non solo per files newLisp), mettetelo in SciTEGlobal.properties

# Right edge
edge.column=100
edge.mode=1
edge.colour=#AAAAAA
Limite destro di scrittura: posizione (colonna 100), attivato (edge.mode=1) e con colore grigio.

# Sizes and visibility in edit pane
line.margin.visible=1
line.margin.width=4
margin.width=14
fold.margin.width=14
fold.margin.colour=#007F00
fold.margin.highlight.colour=#007F00
Caratteristiche del bordo a sinistra dell’editor, cioè la parte in cui compare il numero di riga, i bookmarks, etc…

caret.fore=#FF0000
caret.width=3
caret.period=500

Caratteristiche del cursore: in particolare caret.width rappresenta lo “spessore” del cursore in modo insert (cioè quando ha la forma di una linea verticale, come una pipe).

# Default selected text COLORS.
selection.back=#FFFFFF
selection.alpha=80
Quando selezionate del testo, usando per esempio il mouse, tale selezione compare come se fosse “evidenziata”. Questi sono i parametri di tale evidenziazione. Nel mio codice ho posto un colore di evidenziazione bianco (#FFFFFF) ma con un coefficiente di trasparenza di 80 (0-255).

# Monospace per default
L’intero blocco è necessario per indicare a Scite di usare in ogni circostanza dei fonts MONOSPACE (personalmente detesto scrivere programmi con fonts proporzionali!).

# Code completion
autocompleteword.automatic=1
autocomplete.choose.single=0
lexer.$(file.patterns.flash)=lisp
autocomplete.flash.ignorecase=1
Parametri necessari per il code completion. L’opzione autocomplete.choose.single=0 indica al parser lessicale di non includere solo una opzione in output (come suggerimento), ma tutte le parole chiave che rispettano la parola scritta.

Anche stavolta siamo giunti al termine, alla prossima!





Lavorare con le liste: quando il gioco si fà duro… (parte 2)

6 08 2009

google_translate.gif Translate To English!

Avete “digerito” la prima parte? Ok, allora proseguiamo! Nella prima parte abbiamo parlato anche degli array, gestendoli però con alcuni semplici metodi standard. newLisp però prevede delle funzioni (di cui alcune già viste la volta scorsa) per la manipolazione di liste-array. Prima di tutto, facciamo un “brutale” copia/incolla dal manuale, e vediamo quali funzioni abbiamo a nostra disposizione:

append Appende gli array
array Crea ed inizializza un array fino a 16 dimensioni
array-list Converte un array in una lista
array? Controlla se una espressione è un array
det Ritorna il determinante di una matrice
first Ritorna la prima riga di un array
invert Ritorna l’inversa di una matrice
last Ritorna l’ultima riga di un array
mat Esegue operazioni scalari su matrici
multiply Moltiplica due matrici
nth Ritorna un elemento di un array
rest Ritorna tutti gli elementi di un array tranne il primo
setf Set (imposta) i contenuti di un array per reference
slice Ritorna uno slice (una parte, un sottoinsieme) di un array
sort Mette in ordine gli elementi di un array
transpose Traspone una matrice

Alcune note importanti:

  1. Gli array multidimensionali vengono gestiti come array di array.
  2. Quando usato in modo interattivo, gli array sono mostrati come liste, e non c’è nessun modo per distinguerli.
  3. Gli array possono essere non-rettangolari, ma quando vengono serializzati diventano rettangolari.
  4. La funzione array crea sempre array rettangolari.
La nota più importante di tutte: gli array così creati sono veri array, e non liste! Questo significa che non si possono applicare su di essi tutte le funzioni che normalmente si applicano sulle liste, e che gli array possono fornire “out-of-bounds error” (cosa che non può accadere con le liste).

E allora quando dobbiamo usare gli array? Vanno usati quando si devono gestire GRANDI quantità di dati, ad accesso casuale, i quali risultano troppo lenti per essere gestiti tramite le liste. Per inizializzare un array dobbiamo procedere in questo modo:

> (array 2 3)
((nil nil nil) (nil nil nil))

Se volessimo inserire un elemento all’interno durante la sua creazione, aggiungiamolo con una lista:

> (array 2 3 '(1))
((1 1 1) (1 1 1))
> (array 2 3 (sequence 1 6))
((1 2 3) (4 5 6))
> (array 2 3 '("X"))
(("X" "X" "X") ("X" "X" "X"))

Per inserire un valore nell’array possiamo ricorrere alla funzione setf, che inserirà il valore “by-reference” (quindi è molto veloce):

> (setq mio (array 2 3 '(".")))
(("." "." ".") ("." "." "."))
> (setf (mio 0 1) "X")
"X"
> mio
(("." "X" ".") ("." "." "."))
> (setf (mio 1 2) "Z")
"Z"
> mio
(("." "X" ".") ("." "." "Z"))
Ricordatevi che gli indici partono sempre da zero!

Possiamo anche lavorare con array in altri array:

> (setf (mio 1 0) '(A B C))
(A B C)
> mio
(("." "X" ".") ((A B C) "." "Z"))
> (setf (mio 1 ) '(X Y Z))
(X Y Z)
> mio
(("." "X" ".") (X Y Z))

Nell’ultimo caso ho sostituito un intera dimensione dell’array (in termini di contenuti) con un’altra! Ed ora guardate qui:

> (setf (mio 3 ) '(W A S D))
ERR: array index out of bounds in function setf : 3

Ho cercato di inserire un elemento in un posto inesistente, ed ho ottenuto un Out of bounds. Questo perchè la funzione (setf), lavorando per reference, deve necessariamente lavorare su elementi esistenti (non si può referenziare qualcosa che non esiste!).

Come posso estrarre i dati di una riga? Ed una cella singola? Guardate questi esempi:

> (setq mio (array 4 3 (sequence 0 11)))
((0 1 2) (3 4 5) (6 7 8 ) (9 10 11))
> (mio 1 1)
4
> (mio 1)
(3 4 5)

> (mio -1) ;; INDICE NEGATIVO: LEGGO L'ULTIMO ELEMENTO!
(9 10 11)

Si possono anche estrarre “pezzi” di array, tramite la funzione (slice):

> (slice mio 1 2)
((3 4 5) (6 7 8))

Per essere certi di lavorare con degli array, possiamo usare la funzione (array?):

> (setq mio (array 3 2 (sequence 1 6)))
((1 2) (3 4) (5 6))
> (array? mio)
true
> (array? (array-list mio)) ;; CONVERTO L'ARRAY IN LISTA
nil

> (list? (array-list mio)) ;; CONVERTO L'ARRAY IN LISTA
true

Invece se si vuole convertire una lista in un array, dobbiamo usare la funzione (flat) che si occuperà di “appiattire” la lista e darla in pasto al generatore di array:

> (setq mioArray (array 2 3 (flat lista)))
((1 2 3) (4 5 6))
> (setq mioArray (array 3 2 (flat lista)))
((1 2) (3 4) (5 6))

E’ interessante notare come questo sistema permetta di “distribuire” i valori nell’array, senza preoccuparsi della “forma” dell’array stesso nè della forma della lista.

Prima di concludere (ma la terza parte di questo workshop è già alle porte ;-)  ) vediamo le funzioni (source) (save). Esse permettono di serializzare espressioni, simboli, context, etc… e, ovviamente, array!

Facciamo subito una prova:

> (setq mioArray (array 3 2 (sequence 1 6)))
((1 2) (3 4) (5 6))

> (println (source 'mioArray))
(set 'mioArray (array 3 2 (flat '(
  (1 2)
  (3 4)
  (5 6)))))

"(set 'mioArray (array 3 2 (flat '(\n  (1 2) \n  (3 4) \n  (5 6)))))\n\n"

Ho aggiunto la funzione (println) per comodità di lettura. La funzione (source) genera tutto l’indispensabile per ricrare l’elemento da un’altra parte, o per salvarlo. La funzione (source) fà la stessa cosa, ma salva il codice generato direttamente su file.

Ora pensate al potenziale di queste funzioni, unite alla (net-eval).

Come dite? Non sapete cosa è la (net-eval)?! Ne parleremo in un prossimo workshop, insieme alla programmazione distribuita. Promesso!





Lavorare con le liste: quando il gioco si fà duro… (parte 1)

2 08 2009

google_translate.gif
Translate To English!

Come ormai ben sapete, le liste sono l’elemento cardine di newLisp. Le liste sono validi sostituti degli array, delle hash tables, degli array associativi, etc… Molti linguaggi di programmazione infatti complicano la vita al programmatore inserendo diversi tipi di dato con, ovviamente, funzioni ad-hoc per il loro uso. In newLisp la situazione è diversa: la base di tutto sono le liste. E la cosa più importante è che le funzioni necessarie per il loro uso sono semplicemente perfette. In questo workshop faremo meglio la loro conoscenza. Vi accorgerete quanto sono flessibili. Si inizia! Prima di tutto realizzeremo dei classici: cioè vedremo come implementare (e gestire!) gli stacks (LIFO) e le code (FIFO).

Lavorare con uno stack.

Cosa è uno stack LIFO (Last In First Out, cioè l’ultimo elemento che entra è il primo ad uscire)? Allora, prendete dei libri e poneteli ad uno ad uno all’interno di una scatola, uno sopra all’altro, formando una pila. In cima, dove si trova ilcoperchio è l’unica apertura. Potete facilmente verificare che l’ultimo libro posto sulla pila (messo sopra tutti gli altri), sarà il primo libro che potrete riprendere: LIBRO 3 <— Cima della pila (ultimo libro posto sulla pila) LIBRO 2 LIBRO 1 <— Fondo della pila La regola per implementare uno stack è che i libri non si possono prendere dal mezzo (libro 2), nè dal fondo della pila (libro 1). Per creare un oggetto come questo si usano, ovviamente, li liste ;-) Qui c’è tutta la flessibilità di newLisp, infatti una lista-stack è una comune lista, ma noi la gestiremo  in modo tale da farla comportare come uno stack. Per inserire dati nello stacca usiamo la funzione (push), mentre per estrarre elementi useremo (pop). Ecco un esempio:

> (setq scatola '())
()
> (push 'libro1 scatola)
(libro1)
> (push 'libro2 scatola)
(libro2 libro1)
> (push 'libro3 scatola)
(libro3 libro2 libro1)
>

Notate come l’ultimo libro inserito, libro3, si trova in cima alla lista (primo elemento della lista). Ora preleviamo gli elementi:

> (pop scatola)
libro3
> (pop scatola)
libro2
> (pop scatola)
libro1
> scatola
()
>

La funzione pop preleva l’ultimo elemento inserito. Notate che, ad ogni chiamata pop, gli elementi vengono fisicamente eliminati dalla lista (scatola). Al termine delle tre chiamate pop, la scatola sarà vuota. Semplicissimo!

Lavorare con una coda.

Le code sono contenitori di tipo FIFO (First In First Out). Immaginate un tubo. Esso avrà due “porte di accesso”: una per l’ingresso (le palline entreranno da questa porta), ed una per l’uscita:

ENTRATA –> pallina-rossa –> pallina-verde –> pallina blu –> USCITA

La pallina blu è la prima ad essere entrata (First In) e sarà la prima ad uscire (First Out).
Come implementarlo in newLisp?

> (setq tubo '())
()
> (push 'pallina-blu tubo)
(pallina-blu)
> (push 'pallina-verde tubo)
(pallina-verde pallina-blu)
> (push 'pallina-rossa tubo)
(pallina-rossa pallina-verde pallina-blu)
>

Uso la stessa funzione push per inserire le palline nel tubo. Ora come le prelevo?

> (pop tubo -1)
pallina-blu
> (pop tubo -1)
pallina-verde
> (pop tubo -1)
pallina-rossa
> tubo
()

L’indice “-1″ usato nella funzione pop indica di prelevare l’ultimo elemento della lista, e non il primo. Abbiamo quindi realizzato un contenitore molto diverso dallo stack, ma abbiamo usato gli stessi elementi (una lista, la funzione pop e la push). Semplice, flessibile, efficace.

Creare e manipolare un array.

Cosa è un array? Immaginate un corridoio, molto lungo, con tantissime porte, una dietro all’altra, tutte numerate (0, 1, 2, 3, etc…). Ogni porta dà accesso ad una piccola stanza, in cui depositare qualcosa. Potete mettere oggetti nelle stanze facendo riferimento al numero della stanza. Lo stesso vale per prelevare oggetti da esse. In molti linguaggi di programmazione, gli array hanno una lunghezza fissa, e talvolta possono essere ridimensionati (ma ciò comporta diversi svantaggi: in alcuni linguggi il ridimensionamento viene fatto RICOPIANDO tutti gli elementi in un nuovo array, con grande spreco di risorse e di tempo).
In newLisp gli array possono essere gestiti con… le liste ovviamente! La parte interessante è che abbiamo molteplici strumenti per farlo (funzioni), ognuno con caratteristiche particolari. Sono veramente tante le strade che si possono percorrere per gestire un array, ed alcune di esse si mescolano con il concetto di liste, permettendo quindi una gestione molto più flessibile e dinamica degli array classici. Io vi mostrerò solo le funzioni inerenti ad una gestione tipica di un array, mentre in seguito vedremo come far “esplodere” le vere potenzialità di newLisp e delle sue liste!
Partiamo con un esempio:

> (setq mio-array '(1 2 3 4 5 6 7 8 9 10))
> (setf (mio-array 2) 'X)

(1 2 X 4 5 6 7 8 9 10)

Prima di tutto creiamo una lista con i numeri da 1 a 10. Poi, usando la funzione setf, metto il simbolo X nella stanza numero 2 (cioè la terza stanza del corridoio).
NOTA: il primo numero della stanza vale “0″ (zero), e non “1″. Quindi la stanza “2″ è la terza stanza del corridoio (il linguaggio C, C++, Java, etc… usano tutti questa stessa notazione).
NOTA 2: il valore inserito ha sovrascritto il precedente! Questo è il funzionamento di un array.
Normalmente in un array, leggendo il suo valore, non si elimina tale valore (come invece accade negli stack e nelle code). Vediamo quindi come fare.

> mio-array
(1 2 X 4 5 6 7 8 9 10) <--- mio-array contiene questi valori
> (mio-array 1)        <--- chiedo di leggere il valore contenuto nella stanza numero "1"
2
> (mio-array 2)        <--- chiedo di leggere il valore contenuto nella stanza numero "2"
X
> (mio-array 3)        <--- chiedo di leggere il valore contenuto nella stanza numero "3"
4

Oppure posso usare quest’altro modo (usando la funzione nth):

> mio-array
(1 2 X 4 5 6 7 8 9 10)
> (nth 2 mio-array)
X
> (nth 3 mio-array)
4

Vorrei mettere in evidenza anche quest’altra forma:

> mio-array
(1 2 X 4 5 6 7 8 9 10)
> (2 mio-array)    <--- Ottengo i valori della stanza "2" e seguenti.
(X 4 5 6 7 8 9 10)
> (5 mio-array)    <--- Ottengo i valori della stanza "5" e seguenti.
(6 7 8 9 10)

In quest’ultimo caso vengono letti TUTTI i valori a partire dalla stanza indicata.

Ma come potrei gestire gli array multidimensionali? La risposta è semplice: le liste sono dei “contenitori” di simboli o… altre liste. Un array con n-dimensioni può essere facilmente rappresentato come delle matrici ad n-dimensioni. Le matrici sono facilmente rappresentabili con le liste…

Matrice = [ [1 2] [3 4] ]

Questa matrice la posso rappresentare con un array “tradizionale”, in questo modo:

Matrice[0, 0] = 1
Matrice[0, 1] = 2
Matrice[1, 0] = 3
Matrice[1, 1] = 4

Ecco come scriverlo in newLisp:

> (setq Matrice '( (1 2) (3 4) ) )
((1 2) (3 4))

Come possiamo accedere ai suoi elementi?

> (Matrice 0)
(1 2)
> (Matrice 1)
(3 4)
> (Matrice 1 0)
3
> (Matrice 1 1)
4

Ed ora, che abbiamo visto come implementare gli array con le liste, prima di concludere questo workshop, vi dò una bella notizia: in newLisp esistono gli array! Quelli veri! Li vedremo nella seconda puntata… per ora è tutto! (per quelli che non sanno aspettare, leggete qui – in inglese -)

A presto!