non sono linguaggi di scripting
origini più comuni:
gli altri linguaggi, invece:
aspetti rilevanti:
sei tipi:
non si possono creare nuovi tipi
le funzioni sono valori:
creazione di funzione con la sintassi classica:
function esempio(a, b) print(a, b) return a + b end
chiamata della funzione:
esempio(3, 2)
sintassi alternativa
risultato identico
esempio = function(a, b) print(a, b) return a + b end
come sempre l'assegnamento è in due fasi:
una funzione si può creare e chiamare senza memorizzarla in una variabile
print((function(a) return a + 1 end)(3))
come funziona?
una funzione si può creare e chiamare
senza memorizzarla in una variabile
così come si può fare numeri e stringhe:
print(2 + 12.54)
print("abcd")
una funzione è un valore
come 2, come 12.54 e "abcd"
questi tre valori si possono usare anche senza memorizzarli in una variabile
esempio: 2 viene usato in una somma
analogo con una funzione:
la funzione viene creata e subito usata,
senza metterla in una variabile
come interi e stringhe:
la funzione viene creata e subito usata,
senza metterla in una variabile
usare una funzione = chiamarla con dei valori
print((function(a) return a + 1 end)(3))
la funzione viene creata da
function(a) return a + 1 end
e subito usata con (…)(3)
è come esempio(3)
chiama la funzione passandole il valore 3
i valori si possono memorizzare in una variabile
e poi copiarli in un'altra variabile
a = 12 b = "abcd" c = a d = b
lo stesso si può fare con le funzioni
esempio = function(a, b) print(a, b) return a + b end
crea la funzione e la memorizza in una variabile esempio
altro = esempio
copia il valore di esempio nella variabile altro
ora entrambe le variabili contengono la stessa funzione
esempio(3, 2) altro(3, 2)
vengono usati i valori delle due variabili
usare una funzione = chiamarla
stessa funzione, stesso risultato
una funzione "normale"
si può chiamare per esempio con il valore 23
prima = function(x) print(x + 4) return x + 1 end
una funzione può anche avere come parametro un'altra funzione
seconda = function(a, b) print(b) print(a(b)) end
a questa funzione si può passare la prima funzione
seconda(prima, 2)
così come una funzione può essere passata a un'altra
funzione…
così può essere ritornata
terza = function() temp = function(a) print(a + 10) return a + 5 end return temp end
crea una funzione temp
la ritorna
si può memorizzare in una variabile:
risultato = terza()
si può eseguire usando la variabile:
risultato(2)
una funzione che riceve un'altra funzione
e ne ritorna un'altra ancora
quarta = function(a, b) print(b) print(a(b)) temp = function(a) print(a + 10) return a + 5 end return temp end risultato = quarta(prima, 2) risultato(2)
un formalismo di funzioni
λvariabile . espressione
parallelo in lua:
function(x) { return espressione; }
lambda calcolo visto come un linguaggio di programmazione:
niente interi, somme, stampe
λx.x
analogo:
function(x) { return x; }
funzione identità: ritorna il valore passato
λx.x λx.x
funzione identità passata a se stessa
function(x) { return x; } (function(x) { return x; }
non si capisce?
I = λx.x
parallelo in lua:
I = function(x) { return x; }
equivalente a:
function I(x) { return x; }
non necessarie
ma chiariscono
I = λx.x II
in lua:
I = function(x) { return x; }
I(I)
I = function(x) { return x; }
I(I)
definisce la funzione I
chiama I,
con argomento I stesso
valutazione: come sempre
funzione λx.(… x … x …)
applicata ad argomento a
argomento a al posto di x
evidenziate: le "istruzioni" della funzione
λs.λz.s(z)
lua:
function(s) { return function(z) { return s(z); }; }
con le definizioni:
A = function(s) {
B = function(z) { return s(z); }
return B(s);
}
unica istruzione:
chiamata di funzione
unici valori:
funzioni
si possono definire i numeri interi
si possono calcolare somme, sottrazioni, ecc.
si possono implementare condizionali e cicli
stessa capacità di calcolo degli altri linguaggi di programmazione
tecnicamente: Turing-completo
argomento successivo del corso
le tabelle sono simili ai vettori
t = {24, 4, 8}
t[2] = -342
print(t[1], t[2], t[3])
i valori memorizzati possono essere di tipo qualsiasi
per esempio stringhe
t = {"una", "frase", "memorizzata", "in una tabella"}
print(t[1], t[2], t[3], t[4])
t = {true, 23, "abcd", nil}
print(t[1], t[2], t[3], t[4])
booleano, numero, stringa, nil
q = {}
q[1] = t
print(q[1][2])
q = {}
q[2] = function() print "ecco" end
q[2]()
spesso gli indici sono numeri
t = {24, 4, 8}
t[2] = -342
print(t[1], t[2], t[3])
ma possono anche essere stringhe
t = {}
t["efgh"] = "ijkl"
print(t["efgh"])
possono essere di tipo diverso fra loro
t = {}
t[2] = 4
t["abcd"] = 13
print(t[2], t["abcd"])
possono essere valori qualsiasi
incluse altre tabelle e funzioni
gli indici di una tabella sono valori
di tipo qualsiasi
anche stringhe
t = {}
t["efgh"] = "ijkl"
print(t["efgh"])
possono essere di tipo diverso fra loro
per esempio, un numero e una stringa
t = {}
t[2] = 4
t["abcd"] = 13
print(t[2], t["abcd"])
esempio: una tabella che è indice di un'altra
t = {}
t[2] = 4 --- t è una tabella…
t["abcd"] = 13
r = {}
r[t] = 9 --- è indice di un'altra tabella
print(r[t][2])
altro esempio: una funzione che è indice di una tabella
s = {}
s[2] = 4
s[function() print "cosa" end] = 9
for i,v in pairs(t)
do
print(" ", type(i), i, v)
end
gli oggetti sono tabelle
esiste una sintassi alternativa nello stile orientata agli oggetti
ma per il resto gli oggetti sono tabelle normali
--- crea la tabella
p = {}
--- aggiunge dei campi: punto su un piano, con x e y
p["x"] = 12
p["y"] = 3
print(p["x"], p["y"])
--- stessa cosa, sintassi alternativa in stile oo (orientato agli oggetti)
p.x = 12
p.y = 3
print(p.x, p.y)
un metodo è un elemento della tabella
p["stampa"] = function(self) print(self.x, self.y) end
al posto di self si può usare qualsiasi altro nome di variabile
invocare il metodo
p.stampa(p)
stessa cosa, sintassi in stile oo
p:stampa()
sintassi classica:
function p.scambiati(self) print(self.y, self.x) end
sintassi in stile a oggetti
function p:scambiati() print(self.y, self.x) end
unico caso in cui la variabile si deve chiamare "self",
non va bene un altro nome
invocazione, nei due stili
p:scambiati(p) p:scambiati()
non esistono le classi
una classe sarebbe un nuovo tipo di variabili
non si possono definire nuovi tipi
si usa invece un oggetto prototipo
invece di crearlo da zero, si copiano i campi e i metodi di un altro
q = {}
setmetatable(q, {__index = p})
q.x = -49
q.y = 123
q:stampa()
gli oggetti ereditano sia campi che metodi
r = {}
setmetatable(r, {__index = q})
r.y = 999
r:stampa()
r.x è uguale a q
r:stampa() è un metodo uguale a quello di q
un oggetto si può sempre estendere
nuovi campi e nuovi metodi
esempio: alcuni punti si trovano all'interno di zone delimitate
caratteristiche aggiuntive: zona e sua stampa
cambia anche la precedente funzione di stampa
r.zona = "zona 23"
function r:printobject()
print(self.x, self.y, self.zona)
end
function r:printzona()
print("zona: ", self.zona)
end
r:printobject()
r:printzona()
il nuovo oggetto, quello esteso, è il prototipo della sottoclasse
si può usare per creare altri oggetti della sottoclasse
t = {}
setmetatable(t, {__index = r})
t.x = 12
t.y = 3
t.zona = "zona 9"
t:printobject()
r:printzona()
print(p.x) print(p["x"]) print(p[x])
p.x significa p["x"]
p.x non significa p[x]
notare le virgolette: "x" è una stringa, x una variabile
in questo momento x non è definito
quindi vale nil
quindi p[x] significa p[nil]
è ammesso: vale sempre nil