Introduzione al linguaggio REBOL - Parte 2
Mario Cassani 07 Dicembre 2005
Contents:
1. I blocchi
1.1 Blocchi di dati
1.2 Blocchi di istruzioni
1.3 Blocchi di blocchi
1.4 Blocchi generici
2. Le istruzioni condizionali
2.1 I confronti
2.2 Se avvenisse una condizione allora fai qualcosa...
2.3 ...altrimenti fai qualcos'altro
3. Interruttori e lucine
3.1 Un semplice layout
3.2 Gli interruttori
3.3 L'allineamento
3.4 Le azioni
3.5 I LED e le lucine colorate
3.6 Mettiamo insieme il tutto
3.7 Condiamo con l'algebra di Boole
3.8 Aggiornare la grafica
3.9 Aumentiamo la logica
4. Le funzioni
4.1 Risultato finale
1. I blocchi
Quando vogliamo raggruppare delle cose le mettiamo nello stesso cassetto, o in un'unica scatola.
Quando abbiamo bisogno di riunire delle informazioni o delle istruzioni le scriviamo in un 'block!, un tipo di valore più complesso di quelli 'string! e 'logic!, composto da un insieme di valori (anche di tipi diversi tra di loro) e/o istruzioni.
Un blocco viene delimitato dalle parentesi quadre [ ]
>> type? []
== block!
>>
Come vedremo fra poco possiamo scrivere su più righe quello che va tra la parentesi aperta e quella chiusa.
1.1 Blocchi di dati
In un blocco possiamo inserire dei dati, per esempio un elenco di numeri:
>> [12 2 3 55 89]
== [12 2 3 55 89]
>>
oppure un elenco di stringhe:
[
"Buongiorno!"
"Buonasera!"
"Buonanotte!"
"Salve"
"Arrivederci"
"Ciao!"
]
quando andiamo ad immettere in modalità interattiva un blocco come quello sopra accade qualcosa di particolare:
>> [
[ "Buongiorno!"
[ "Buonasera!"
[ "Buonanotte!"
[ "Salve"
[ "Arrivederci"
[ "Ciao!"
[ ]
== [
"Buongiorno!"
"Buonasera!"
"Buonanotte!"
"Salve"
"Arrivederci"
"Ciao!"
]
all'inizio di ogni riga, finchè non chiudiamo correttamente le parentesi, viene ristampata la parentesi quadra.
Questo ci aiuta ad evitare gli errori più grossolani con le parentesi.
1.2 Blocchi di istruzioni
Dentro un blocco può esserci una sequenza di comandi ed istruzioni, come nel seguente caso:
[
a: "Ciao"
print a
print (15 * 3)
]
che, in modalità interattiva, non viene eseguito:
>> [
[ a: "Ciao"
[ print a
[ print (15 * 3)
[ ]
== [
a: "Ciao"
print a
print (15 * 3)
]
ma solo preso come risultato.
1.3 Blocchi di blocchi
Una cosa che posso fare in REBOL é quella di nidificare i blocchi, cioé inserirne più di uno dentro l'altro:
[
[
"Stringa 1.1"
"Stringa 1.2"
]
[
"Stringa 2.1"
"Stringa 2.2"
]
[
"Stringa 3.1"
"Stringa 3.2"
]
]
1.4 Blocchi generici
Come spiegato all'inizio il blocco può contenere anche dati disomogenei:
>> type? [[true false] 1 {Ciao} [[["abcde"] ["vwxyz"]] "Blocco" 'print] 'probe]
== block!
>>
Per migliorare la leggibilità la stessa cosa si può anche scrivere nel seguente modo, magari in uno script:
type? [
[
true
false
]
1
{Ciao}
[
[
["abcde"]
["vwxyz"]
]
"Blocco"
'print
]
'probe
]
Come si può osservare si distinguono i "livelli" più interni, nidificati.
Informazioni sullo stesso livello risultano allineate alla stessa colonna.
Il rientro normalmente usato con il REBOL é di 4 spazi.
In alcuni casi i blocchi possono contenere tipi di dati organizzati, seppur disomogenei.
Lo vediamo in questo esempio dove assegnamo alla variabile di nome registro un blocco:
registro: [
{Dino Bianchi} 8 false
{Gino Rossi} 4 true
{Lino Verdi} 6 true
]
all'interno del blocco abbiamo, ripetutamente, una stringa, un numero ed un valore logico che potrebbero rappresentari i dati sul registro di ciascun alunno di una classe: nome e cognome, voto, interrogato.
Con queste informazioni andiamo sempre più vicini alla comprensione del dato che é programma e del programma che é un insieme di dati.
2. Le istruzioni condizionali
Oltre alle istruzioni qui illustrate ne esistono altre, più complesse ma, per iniziare e non confonderci troppo possiamo cominciare da ciò che é essenziale: 'if ed 'either.
Le istruzioni logiche eseguono un blocco di istruzioni in base ad un risultato o ad un valore logico, fosse anche contenuto in una variabile.
2.1 I confronti
A questo punto serve spiegare che i confronti si fanno in questi modi:
< Minore
= Uguale
> Maggiore
<= Minore o uguale
>= Maggiore o uguale
<> Diverso
e restituiscono un valore logico: vero o falso, 'true o 'false.
Questo é interessante: se i confronti sono dei valori di tipo logic! li posso combinare con l'algebra di Boole:
(numero > 10) and (numero =< 100)
2.2 Se avvenisse una condizione allora fai qualcosa...
Sappiamo stampare delle informazioni, fermare in modo interattivo l'interprete, assegnare conforntare e verificare le variabili, conosciamo alcuni tipi diversi di valori.
Se scrivessimo dei programmi con quello che abbiamo, però, avremmo sempre qualcosa di ripetitivo, senza variazioni sul tema.
Quando parlo con un'altra persona per spiegargli cosa deve fare o insegnargli il modo di portare a termine un lavoro, per descrivergli che, in alcuni casi, occorre comportarsi in modo diverso gli direi:
"SE succede la tal cosa allora fai qualcos'altro"
Con il REBOL accade la stessa cosa ed, essendo il "se" inglese "if" lo faccio seguire dalla condizione e da un blocco di istruzioni da eseguire nel caso la condizione sia vera:
if (numero = 10) [
print "DIECI!"
]
dove numero é una variabile numerica che, venendo confrontata con il numero 10, mi restituisce un valore 'logic! come condizione.
Vediamolo in uno script:
REBOL [
Title: "Se ... allora ..."
Author: "Mario Cassani"
]
numero: 5
if (numero = 10) [
print "DIECI!"
]
print {Sono a metà}
numero: 10
if (numero = 10) [
print "DIECI!"
]
print {Ho terminato}
Nel primo caso la variabile numero vale 5 per cui il programma non stampa nulla, nel secondo numero vale proprio 10 e lo script stamperà "DIECI!".
Le scritte "Sono a metà" ed "Ho terminato" vengono sempre e comunque scritte, indipendentemente dal fatto che la condizione (numero = 10) sia vera o falsa.
2.3 ...altrimenti fai qualcos'altro
Quello che ho visto non mi basta.
Cosa dovrei fare se volessi fare qualcosa nel caso la condizione sia vera e qualcosa di diverso qualora fosse falsa?
La soluzione non sarebbe difficile:
if (numero = 10) [
print "DIECI!"
]
if not (numero = 10) [
print "ALTRO"
]
stampa "DIECI!" se numero fosse 10 ed "ALTRO" se numero non fosse 10.
Non é proprio il massimo: devo ripetere lo stesso confronto due volte.
Parlando con la solita persona per spiegargli come svolgere un lavoro al mio posto direi:
"O succede la tal cosa e allora fai la prima cosa O fai l'altra cosa".
In inglese "O... O..." diventa "EITHER... OR...", semplificando un po':
either (numero = 10) [
print "DIECI!"
] [
print "ALTRO"
]
esattamente equivalente a quanto scritto sopra ma molto più elegante e meno ripetitivo.
3. Interruttori e lucine
Giunti a questo punto non ci basta più vedere delle scritte stampate sullo schermo siano esse stringhe, variabili o risultati.
Sarebbe anche interessante poter interagire con il programma che scriviamo.
Il REBOL/View ci mette a disposizione un dialetto speciale per gestire l'interfaccia grafica: VID.
Esso ci fornisce: finestre, bottoni, immagini ed altri interessanti oggetti grafici semplici da gestire.
Parliamo di dialetto per indicare un gruppo di simboli, 'word, che assumono un particolare significato o funzione in uno specifico contesto.
In questo caso il contesto é l'interfaccia grafica, realizzata tramite un "layout".
3.1 Un semplice layout
Un blocco contenente informazioni nel dialetto VID può essere trasformato in layout e visializzato.
Partiamo da un semplice blocco:
[
text "Ecco un testo"
]
facciamolo riconoscere come layout al REBOL:
layout [
text "Ecco un testo"
]
e, magari, visualizziamolo anche.
Qui provare quanto scritto trascrivendolo nell'interprete REBOL diviene indispensabile:
view layout [
text "Ecco un testo"
]
Possiamo vedere che compare una finestra con una scritta, quella indicata nel blocco, dopo 'text.
3.2 Gli interruttori
Chiudiamo la finestra ed aggiungiamo qualcosa:
view layout [
text "Interruttore acceso"
toggle "Vero" "Falso"
]
Qui, oltre alla scritta abbiamo anche un interruttore che può assumere due posizioni con due differenti scritte.
Un altro piccolo passo:
view layout [
text "Interruttore A"
toggle "Vero" "Falso"
text "Interruttore B"
toggle "Vero" "Falso"
]
sempre meglio: due scritte e due interruttori ma, qualcosa, non va...
3.3 L'allineamento
Sarebbe meglio allineare diversamente scritte ed interruttori:
view layout [
across
text "Interruttore A"
toggle "Vero" "Falso"
text "Interruttore B"
toggle "Vero" "Falso"
]
ci siamo quasi, a questo punto sarebbe meglio mettere ogni scritta con il relativo interruttore su una riga differente:
view layout [
across
text "Interruttore A"
toggle "Vero" "Falso"
return
text "Interruttore B"
toggle "Vero" "Falso"
]
giochiamoci per un po' e, presto, ci stufiamo: premere gli interruttori non produce nulla!
L'allineamento predefinito non é 'across, ma 'below
Se lo si volesse ripristinare dopo un 'across bisogna
riscriverlo.
3.4 Le azioni
Per migliorare il tutto non ci resta che associare un'azione all'interruttore.
Lo faccio passando un blocco di istruzioni al 'toggle:
view layout [
across
text "Interruttore A"
toggle "Vero" "Falso" [
print value
]
return
text "Interruttore B"
toggle "Vero" "Falso" [
print value
]
]
'value é il valore che assume l'oggetto grafico (in questo caso l'interruttore).
3.5 I LED e le lucine colorate
Facciamo qualcosa di più colorato, mettiamo una "lucina" in una finestra:
view layout [
led true
]
la luce é verde perchè abbiamo passato il valore vero, 'true, al 'led.
Cosa accade mettendo 'false come valore?
view layout [
led false
]
una bella lucina rossa.
3.6 Mettiamo insieme il tutto
Il problema, a questo punto, é che sono incontentabile e mi piacerebbe tanto far cambiare colore alla lucina e non semplicemente decidere all'inizio di che colore sia.
3.6.1 Diamo un nome alle cose
Per poter cambiare qualcosa dovrei identificarlo, dargli un nome.
Abbiamo già visto che possiamo assegnare qualcosa ad una variabile.
Neanche interruttori e lucine fanno eccezione, per nostra fortuna:
view layout [
across
lucina-a: led true
text "Interruttore A"
interruttore-a: toggle "Vero" "Falso" [
print value
]
return
lucina-b: led true
text "Interruttore B"
interruttore-b: toggle "Vero" "Falso" [
print value
]
]
i nomi ci sono ma continuo a non sapere come cambiare le lucine premendo gli interruttori corrispondenti.
3.7 Condiamo con l'algebra di Boole
- Per cambiare il valore di un led devo cambiare i dati al suo interno da vero a falso o viceversa (in questo caso lo faccio negando il valore)
view layout [
across
lucina-a: led true
text "Interruttore A"
interruttore-a: toggle "Vero" "Falso" [
lucina-a/data: not lucina-a/data
]
return
lucina-b: led true
text "Interruttore B"
interruttore-b: toggle "Vero" "Falso" [
lucina-a/data: not lucina-a/data
]
]
ma non funziona!
Prima di cercare rimedio a questo problema vorrei sottolineare il modo con cui ho cambiato o letto il valore delle lucine:
ATTENZIONE
VARIABILI E RIASSEGNAMENTO
REFINEMENT
3.8 Aggiornare la grafica
Devo anche sapere che:
- Per aggiornare un oggetto grafico devo usare l'istruzione 'show
view layout [
across
lucina-a: led true
text "Interruttore A"
interruttore-a: toggle "Vero" "Falso" [
lucina-a/data: not lucina-a/data
show lucina-a
]
return
lucina-b: led true
text "Interruttore B"
interruttore-b: toggle "Vero" "Falso" [
lucina-b/data: not lucina-b/data
show lucina-b
]
]
3.9 Aumentiamo la logica
Possiamo mettere qualche altro led, con un commento di testo, per visualizzare i risultati delle operazioni logiche su gli interruttori A e B.
A questo scopo dobbiamo ricordarci di aggiornare tutti i led coinvolti dalla pressione di ciascun interruttore.
Ci torna comodo sapere che 'show accetta, come argomento, un blocco con l'elenco degli oggetti grafici da aggiornare.
Nell'esempio che segue uso il metodo di aggiornamento senza blocco con l'interruttore A e quello con il blocco per l'interruttore B:
view layout [
across
lucina-a: led true
text "Interruttore A"
interruttore-a: toggle "Vero" "Falso" [
lucina-a/data: not lucina-a/data
show lucina-a
lucina-c/data: (lucina-a/data and lucina-b/data)
show lucina-c
lucina-d/data: (lucina-a/data or lucina-b/data)
show lucina-d
lucina-e/data: (lucina-a/data xor lucina-b/data)
show lucina-e
lucina-f/data: (not lucina-a/data)
show lucina-f
]
return
lucina-b: led true
text "Interruttore B"
interruttore-b: toggle "Vero" "Falso" [
lucina-b/data: not lucina-b/data
lucina-c/data: (lucina-a/data and lucina-b/data)
lucina-d/data: (lucina-a/data or lucina-b/data)
lucina-e/data: (lucina-a/data xor lucina-b/data)
show [lucina-b lucina-c lucina-d lucina-e]
]
return
lucina-c: led (lucina-a/data and lucina-b/data)
text "A and B"
return
lucina-d: led (lucina-a/data or lucina-b/data)
text "A or B"
return
lucina-e: led (lucina-a/data xor lucina-b/data)
text "A xor B"
return
lucina-f: led (not lucina-a/data)
text "not A"
]
La cosa comincia a farsi interessante, se non fosse per quell'elenco di nomi di lucine ed interruttori da aggiornare ogni volta...
4. Le funzioni
4.1 Risultato finale
Ecco il nostro programmino in tutto il suo splendore:
REBOL [
Title: "Interruttori logici"
Author: "Mario Cassani"
]
aggiorna-luci: does [
lucina-a/data: not interruttore-a/data
lucina-b/data: not interruttore-b/data
lucina-c/data: (lucina-a/data and lucina-b/data)
lucina-d/data: (lucina-a/data or lucina-b/data)
lucina-e/data: (lucina-a/data xor lucina-b/data)
lucina-f/data: (not lucina-a/data)
show [lucina-a lucina-b lucina-c lucina-d lucina-e lucina-f]
]
view layout [
across
lucina-a: led true
text "Interruttore A"
interruttore-a: toggle "Vero" "Falso" [
aggiorna-luci
]
return
lucina-b: led true
text "Interruttore B"
interruttore-b: toggle "Vero" "Falso" [
aggiorna-luci
]
return
lucina-c: led (lucina-a/data and lucina-b/data)
text "A and B"
return
lucina-d: led (lucina-a/data or lucina-b/data)
text "A or B"
return
lucina-e: led (lucina-a/data xor lucina-b/data)
text "A xor B"
return
lucina-f: led (not lucina-a/data)
text "not A"
]
Non ci resta che copiarlo e provarlo.
|