Archivi Categorie: Lua

Corso Lua & …

Un po’ di notizie, una importante, altre che forse interessano solo me (io). luaBella e intrigante l’immagine vero? Di quello dopo, prima la pubblicità 😉 Ieri ho raggiunto una tappa tapposa sul mio social-coso preferito: 7777OK, lo so che non interessa, come neppure –forse– che ho aggiornato J, lo script di cui avevo raccontato qui: J una nuova utility vecchia di 30+ anni. La nuova versione –proprio come faceva su Pr1me– permette di accedere a una sub-directory passandogli il nome come secondo parametro, così: JSemplice vero? OK, lo so ma a me piace. Notare il TUTTO MAIUSCOLO, rinko-in-progress? Chissà… 🙄 Ah, sì! cercato per un editor per il Lisp, per la formattazione automatica. Qualcosa c’è ma non molto e mi sa che SLIME… 😉


Ma basta con queste cosette il motivo vero del post è che Roberto Giacomelli ha iniziato il corso di Lua promesso tempo fa sul blog LUBIT LINUX, quello di Luigi Bit3Lux Iannoccaro. Personalmente ho usato Lua per un progetto poi abbandonato per ragioni tutt’altro che belle, anzi bruttissime. Ma è roba passata, dello scorso millennio (o era già iniziato questo?). Lua ha una storia tutta, sua, brasiliana, c’è di mezo anche il samba (o sono io che mi confondo?). Ha una caratteristica che lo differenzia dagli usuali linguaggi di scripting. Non so se devo dirlo, non vorrei che poi pensate meh…! Ma dai, cito la Wiki, poi non ne parliamo più: Lua is a lightweight multi-paradigm programming language designed as a scripting language with extensible semantics as a primary goal. Ecco l’ho detto, suona bene, vero? Adesso lo riprendo, c’è il corso di Roberto. Anzi ieri è uscita la prima puntata: Corso Lua – puntata 1. Buon lavoro & auguri. Forse l’ho già detto che Robitex rockz, seguite il corso e mi darete ragione 😀

Il termine dell’appalto

Sommario

Calcoleremo la data di termine di un appalto a partire da quella di inizio lavori dal numero di giorni naturali e consecutivi stabiliti dal contratto, utilizzando due linguaggi di programmazione: Lua e Go.

L’occasione

Potevamo utilizzare un banale foglio di calcolo per determinare la data del termine di fine lavori per un contratto d’appalto? No… No perché ci si annoia sempre a fare le stesse cose e sentiamo la necessità di migliorarci.

Calcolo

La descrizione del calcolo che seguiremo è presto fatta: alla data di inizio sommiamo il numero di giorni stabiliti per completare l’opera e togliamo un giorno, per ottenere così la data cercata corrispondente al termine dei lavori.

Infatti, il giorno della consegna conta già uno ai fini del tempo contrattuale. Possiamo vedere la cosa considerando l’istante di tempo della mezzanotte: è al contempo il primo istante del giorno ma anche l’ultimo di quello precedente.
Tuttavia la mezzanotte è sempre interpretato come il primo istante del giorno successivo. Per la data di inizio è corretto ma non per la data di termine.

Lua

In Lua, utilizzando le funzioni della libreria interna “os”, costruiamo la data di inizio lavori che viene gestita come il numero di secondi trascorsi da un certo momento (il classico epoch Unix). Sommiamo poi il numero di secondi corrispondenti alla durata dell’appalto, sottraendovi un secondo per ottenere l’attimo prima della fine dell’ultimo giorno di lavoro.
La funzione termina restituendo la stringa della data formattata eventualmente come specificato nell’ultimo argomento facoltativo.

-- restituisce la data di scadenza dell'appalto
-- nota la data di consegna ed il numero di
-- giorni naturali e consecutivi della durata
-- dei lavori contrattuali

local function endingDate(d,m,y, days, frmt)
    local secsperday = 24*60*60
    local t_start = os.time{day=d,month=m,year=y,hour=0}
    local t_end   = t_start + days*secsperday -1
    frmt = frmt or "%d/%m/%Y"
    return os.date(frmt, t_end)
end

print(endingDate(26,8,2013, 60))

Go

Anche in Go utilizziamo la libreria disponibile con il linguaggio, in particolare il pacchetto “time”, per restituire nello stesso formato precedente la data risultato.

package main

import (
    "time"
    "fmt"
)

func main() {
    fmt.Println(endingDate(2013,8,26, 60))
}

func endingDate(y int, m time.Month, d, days int) string {
    s := time.Date(y, m, d, 0, 0, 0, 0, time.UTC)
    e := s.AddDate(0, 0, days).Add(-time.Second)
    return fmt.Sprintf("%d/%02d/%d",e.Day(), e.Month(), e.Year())
}

Finale

Le differenze con Lua possono sembrare ad un primo sguardo minime, ma non è così anche se entrambi hanno feature in comune come il supporto alla concorrenza, le funzioni di prima classe e le closure.

Io, la prima cosa che ho notato è la maggiore precisione della libreria “time” di Go rispetto a Lua (che si riflette nel modo in cui percepiamo le date), e l’uso trasparente in Go di tipi sinonimi di quelli di base come per esempio nella rappresentazione del mese — il tipo time.Month per intenderci.

Penso però che la differenza sostanziale sia nell’importanza che il linguaggio da ai tipi: in Lua la tipizzazione è dinamica come si conviene per un linguaggio di scripting mentre in Go è statica: nel codice occorre sempre definire il tipo di dato e solo rispetto a questa classificazione i dati possono essere elaborati, per esempio da una funzione).

Il risultato è che in Go si è maggiormente portati a pensare concettualmente ai dati come termini del problema, strutturando il codice. Ovvio che questa differenza è la stessa che troviamo confrontando qualsiasi coppia di linguaggi con tipi dinamici e statici (come Python e Java), ma il Go è certamente uno dei linguaggi a tipi statici che si avvicinano di più ai linguaggi a tipi dinamici…

Un saluto.
R.

A proposito di Fibonacci…

Sommario

La semplice funzione per generare la serie di Fibonacci può essere scritta in Go sfruttando le closure.

Fibonacci

Ne abbiamo parlato nel post precedente, ma la sequenza di Fibonacci ha ancora qualcosa da farci scoprire, almeno dal punto di vista del linguaggio di programmazione Go.

Avevano scritto la funzione che calcola l’ennesimo numero della serie a partire dalla definizione della serie: il numero successivo è la somma dei due numeri precedenti. Il codice è quindi il seguente:

package main

// ennesimo numero della serie di Fibonacci
func fibonacci(n int) int {
    var a, b int = 0, 1
    for i := 0; i < n-1; i++ {
        a, b = b, a+b
    }
    return a
}

func main() {
    for i := 1; i < 10; i++ {
        print(fibonacci(i), " ")
    }
    println()
}

Funzioni di prima classe

Quando le funzioni sono tipi di prima classe possono essere trattate come valori, dunque possono essere assegnate a variabili e restituite da una funzione.
Questa prerogativa dei linguaggi funzionali è presente in Lua ed anche in Go (quello che diremo vale indifferentemente per i due linguaggi). Per fare un esempio in Go, assegnamo una funzione ad una variabile per il calcolo della somma degli argomenti interi (ricordo che per provare il codice possiamo utilizzare il comodo servizio web Playground:

package main

func main() {
    add := func(a, b int) int {
        return a + b
    }
    println(add(4,5))
}

Assegnare una funzione ad una variabile significa creare una funzione anonima (senza nome) ma, rispetto alla definizione diretta, cambia solamente la semantica/sintassi del linguaggio ma non il risultato che è esattamente equivalente.

Un esempio con una funzione factory è il seguente dove rispetto ad un simbolo passato come argomento, una funzione restituisce la funzione dell’operazione corrispondente:

package main

func operation(op string) func(int, int) int {
    switch op {
    case "+":
        return func(a, b int) int {
            return a + b
        }
    case "-":
        return func(a, b int) int {
            return a - b
        }
    case "*":
        return func(a, b int) int {
            return a * b
        }
    case "/":
        return func(a, b int) int {
            return a / b
        }
    default:
        return nil
    }
}

func main() {
    add := operation("+")
    println(add(4, 5))
    molt := operation("*")
    println(molt(4, 5))
}

Closure

Quando una funzione di prima classe ha accesso alle variabili locali, le variabili che appartengono allo stesso scopo della funzione, viene chiamata closure.

Tornando a Fibonacci, poiché sono necessari due valori iniziali di innesco della serie, possiamo esprimerli con variabili locali di una closure:

package main

// fibonacci is a function that returns
// a function that returns an int
func fibonacci() func() int {
    a, b := 1, 0
    return func() int {
        a, b = b, a + b
        return a
    }
}

func main() {
    f := fibonacci()
    for i := 0; i < 10; i++ {
        println(f())
    }
}

Le variabili a e b interne alla funzione fibonacci() sono variabili che possono essere lette e scritte dalla funzione anonima, verificando il concetto di funzione closure.
A questo punto possiamo anche creare funzioni di Fibonacci a piacere definendo di volta in volta i primi due numeri della sequenza:

package main

// fibonacci is a function that returns
// a function that returns an int
func fibonacci(n1, n2 int) func() int {
    return func() int {
        n1, n2 = n2, n1 + n2
        return n1
    }
}

func main() {
    f1 := fibonacci(1, 0)
    for i := 0; i < 10; i++ {
        println(f1())
    }
    println()
    f2 := fibonacci(50, 17)
    for i := 0; i < 10; i++ {
        println(f2())
    }
}

Ed in Lua?

-- Lua version : - )
 
-- fibonacci is a function that returns
-- a function that returns an int
function fibonacci(n1, n2)
    return function()
        n1, n2 = n2, n1 + n2
        return n1
        end
end
 
f1 = fibonacci(1, 0)
for i=1,10 do
    print(f1())
end

print()
f2 = fibonacci(50, 17)
for i=1,10 do
    print(f2())
end

Insomma possiamo dire che i progettisti del Go hanno studiato in modo approfondito anche Lua e Python. O no? 🙂

Alla prossima…
Un saluto.
R.