Realizzare le closures (chiusure) in newLisp

29 05 2008

google_translate.gif Translate To English!

Qualche giorno fa` mi sono imbattuto in un argomento affascinante quanto “spinoso”: le closures. Cosa sono?
In breve (e per farla semplice), una chiusura e` una funzione che viene valutata in un ambiente da cui ha effettuato il bind delle variabili con l’ambiente da cui viene chiamata. Ok ok, ho capito che non si e` capito molto! Le definizioni non sempre spiegano qualcosa al meglio! Passiamo allora ad un esempio pratico.

Cerchero` di spiegare cosa sono le closures utilizzando un linguaggio “astratto”, giusto per apprenderne il concetto base, poi passeremo all’implementazione in newLisp (per chi conosce java, diciamo che una closure e` assimilabile ad una inner class, mentre per chi conosce javascript una closure e` una funzione in un’altra funzione).

Analizziamo il codice seguente (astratto, cioe` non scritto in nessun linguaggio di programmazione in particolare):

FUNCTION moltiplicaFattore(argFattore) {
  return(
    FUNCTION(argValore ) {
      return argValore * argFattore
    }
  )
}

Come si usa?

>> calcola_3 = moltiplicaFattore( 3 )
>> calcola_3( 5 )
15
>>

Ora forse iniziate ad intuire qualcosa… analizziamo il codice in dettaglio.
Lo scopo e` quello di realizzare un generatore di funzioni in grado di moltiplicare un valore ( calcola ) per un coefficiente dato ( moltiplicaFattore ).
Prima di tutto ho creato una funzione chiamata moltiplicaFattore() a cui passo un coefficiente, il quale rappresenta il fattore da moltiplicare. Quindi se gli passo “4″, potro` fare calcoli tipo: (3 * 4), oppure (12 * 4), oppure (897 * 4). Quando chiamo questa funzione, essa mi restituisce una nuova funzione, che accetta un solo altro parametro, il quale altro non e` che il valore che voglio moltiplicare per il coefficiente precedentemente dato.

La caratteristica peculiare di queste due funzioni e` che, in quella interna, sfrutto una variabile assegnata in un momento precedente. Questo si puo` fare perche` la funzione interna e` legata al contesto delle variabili definite per moltiplicaFattore(), quindi tale funzione puo` usare le variabili definite in moltiplicaFattore(), anche se essa viene poi richiamata in modo indipendente (vedi esempio: calcola_3( 5 ) ).

In javascript si realizza una cosa simile con il codice seguente (javascript ha le closures):

function moltiplicaFattore(argFattore) {
  return( function(argValore) { return(argFattore * argValore ) ; } );
}

newLisp purtroppo non supporta le closures, in quanto il linguaggio e` dynamically scoped, quindi ad ogni chiamata di funzione i simboli che vanno in conflitto con quelli definiti nello spazio dei nomi della funzione chiamante vengono automaticamente “accantonati” nello stack. Quindi:

(define (contenitore arg1)
    (fn (arg2)
      (println "Arg1: " arg1 " --> Arg2: " arg2 )
    )
  )

Dara` come risultato:

>> (setq mioContenitore (contenitore "pippo" ) )
>> (mioContenitore "B" )
Arg1: nil --> Arg2: B

Poiche`, come recita il manuale, ogni simbolo non espressamente definito viene automaticamente definito ed inizializzato a nil, allora il simbolo arg1 chiamato nella funzione lambda viene inizializzato a nil (vedi output), mentre arg2 viene regolarmente assegnato.

Ora che abbiamo capito (!) cosa sono le closures, e abbiamo anche capito che newLisp non le supporta, come possiamo fare per implementarle ugualmente senza fare le cose troppo “sporche”?

Furtunatamente newLisp ci fornisce un altro strumento, altrettanto potente ed utile: i context.

Un context e` un modo che si usa per separare fisicamente i simboli uguali ma con significati diversi, dando loro la possibilita` di “vivere” in aree diverse (lo spazio dei nomi). E` grazie ai context che possiamo implementare funzionalita` tipiche dei lexically scoped enviroments, le cui funzioni si “comportano” in modo diverso in base al contesto in cui si trovano. Forse, con un azzardo, facendo un paragone con un linguaggio ad oggetti imperativo, potremmo dire che il nostro context sia una classe di un oggetto, mentre le funzioni sono i metodi dell’oggetto stesso.
Passiamo subito alla pratica! Scriviamo allora un programmino in newLisp che realizzi (simuli…) una closure. Dopo aver letto un po` di materiale e soluzioni possibili, sono giunto al seguente codice:

(define (MoltiplicaFattore:MoltiplicaFattore argFattore )
	(if (number? MoltiplicaFattore:fattore )             ; IF
		(* argFattore MoltiplicaFattore:fattore )    ; THEN
		(setq MoltiplicaFattore:fattore argFattore ) ; ELSE
        );if
)

La funzione e` molto compatta, e data la sua struttura e` facilmente riadattabile in altri ambiti. Si usa cosi:

>> ((new 'MoltiplicaFattore 'calcola_3 ) 3 )
>> (calcola_3 8 )
24

Il “trucco” e` nello sfruttare alcune caratteristiche dei context:

  1. Un context puo` includere un functor, cioe` una funzione che viene richiamata per default se non ne viene chiamata nessuna in modo esplicito.
  2. Da un context posso derivarne altri, tramite la funzione new.

Se osservate il programma, vi accorgerete che ho definito un nuovo context chiamato MoltiplicaFattore, al cui interno definisco una variabile chiamata fattore. La prima volta che create il context (e viene chiamato per default il functor MoltiplicaFattore:MoltiplicaFattore) mi “accorgo” che la variabile fattore non e` stata ancora definita (tramite la funzione number? ), e quindi creo la variabile fattore impostandola a argFattore. Le volte successive che richiamo il context (quello nuovo appena istanziato, cioe` calcola_3) la variabile interna al context fattore ora e` definita, e quindi la uso come parametro! ;-)

Questo metodo ci permette anche di cambiare la radice di moltiplicazione:

(setq MoltiplicaFattore:fattore 5 )

Riprendendo il precedente esempio (che riscrivo completamente, per comodita` di lettura)…

>> ((new 'MoltiplicaFattore 'calcola_3 ) 3 )
>> (calcola_3 8 )
24
>> (setq calcola_3:fattore 5 )
>> (calcola_3 8 )
40

Vittoria! Ora abbiamo anche noi le nostre closures! :-)

Bene, ora ci meritiamo proprio una pausa… fino al prossimo articolo!

A presto!!!





Creazione di menu per programmi console

23 05 2008

google_translate.gif Translate To English!

Introduzione

Un po` di tempo fa` ho avuto la necessita` di creare una piccola applicazione, in modalita` console, che mi aiutasse nella manutenzione di alcuni server che abbiamo in azienda. Anche se siamo nell’epoca del web, le applicazioni console sviluppate in newLisp offrono ancora alcuni vantaggi:

  1. Possono essere usate da remoto anche con una larghezza di banda molto ridotta.
  2. Possono essere usate sia in locale sia in remoto (sfruttando anche la capacita` che ha l’interprete newLisp di funzionare come server telnet).
  3. Poiché la parte grafica e` quasi zero (c’è solo da impaginare in modo dignitoso il testo mostrato!) ci si può concentrare di più nello sviluppo degli algoritmi necessari (a parità di tempo disponibile).
  4. newLisp permette di sviluppare agevolmente applicazioni testo che si appoggiano pero` a dei server web (e newLisp può funzionare anche come server web!).
  5. Possono essere usate da qualunque PC che abbia una console (e se un PC ha un browser web ha certamente anche una console, ma non e` vero il contrario!).

Il problema…

Nello sviluppare un software spesso ci si trova ad implementare alcune funzionalita` che, nel tempo, tendono inevitabilemente a diventare sempre piu` numerose (l’appetito vien mangiando!). Si e` quindi di fronte al problema di dover aggiungere nuove opzioni inizialmente non previste. Ovviamente il programma che io stavo realizzando non e` sfuggito a questa “crudele” realta`! Avevo creato un semplice menu iniziale (4 voci), che sono in breve tempo diventate oltre 10 (ma crescevano inesorabilmente!). Avevo quindi deciso di creare dei sottomenu, con l’evidente problema di gestione (le mie funzioni iniziali non prevedevano menu in cascata, ho quindi dovuto effettuare cambiamenti abbastanza pesanti). Stufo della situazione, ho deciso di attingere a piene mani alle potenzialita` di newLisp.

La soluzione!

Lo scopo e` quello di creare un menu testuale molto flessibile, nidificato, che sia componibile come le costruzioni (i famosi mattoncini Lego!). Ecco un esempio:

-----------------------------------
Menu Iniziale
-----------------------------------
A) Anagrafica utenti
B) Dipendenti azienda
C) Reports e statistiche

  -----------------------------------
  Anagrafica utenti
  -----------------------------------
  NEW)  Nuovo utente
  EDIT) Modifica utente
  DEL)  Elimina utente

  -----------------------------------
  Dipendenti azienda
  -----------------------------------
  B1) Inserisci nuovo dipendente
  B2) Licenzia dipendente!

  -----------------------------------
  Reports e statistiche
  -----------------------------------
  REP.PDF)  Reports in PDF
  REP.HTML) Reports in HTML

Nel risolvere questo problema mi sono impegnato a non seguire la strada che avrei intrapreso con un linguaggio imperativo (io sono nato con quelli, quindi qualche volta e` difficile pensare in modo diverso!). Ho cercato allora di sfruttare alcune peculiarita` dei linguaggi funzionali, quali l’uso dei simboli (che mi permettono di scrivere indistintamente sia codice che dati!), la ricorsione (che in newLisp si usa molto piu` frequentemente che nei linguaggi imperativi, dove i classici cicli for, while, etc… sono consigliati), la valutazione del codice a runtime (eval), etc… Quello che ho realizzato e` quindi una piccola funzione, chiamata show-menu (la funzione che gestisce questi menu, completa di ogni accessorio -commenti, buona indentazione, opzioni extra- , e` meno di di 50 righe di codice, mentre il “core”, e` meno di 10 righe!). L’idea e` di creare una lista che possa contenere sia il testo del menu sia le funzioni da eseguire dopo una scelta di una opzione da parte dell’utente. Notate che le opzioni non sono numerate, cio` significa che il nostro menu accetta scelte codificate in modo diverso (REP.PDF, B1, A1, NEW, etc…) La parte “difficile” e` stata nel creare una struttura estremamente flessibile, che fosse in grado di “sopportare” modifiche future, anche pesanti. Il risultato e` stato il seguente (questo e` un esempio di come e` fatta la struttura che “disegna” i menu). Esiste una sola funzione, chiamata show-menu, che si occupa di mostrare il menu, leggere l’input dell’utente, e decidere cosa fare in base alle informazioni ad essa fornite. Ecco come funziona:

(show-menu { testo_del_menu } ( lista_scelte ) )

testo_del_menu e` una stringa (multiline) che “disegna” il menu, come dovra` poi apparire nella console. Quindi potremmo avere:

(setq mainMenu {
-----------------------------------
Menu Iniziale
-----------------------------------
A) Anagrafica utenti
B) Dipendenti azienda
C) Reports e statistiche } )

La lista_scelte invece e` una lista che contiene gli item selezionabili (A, B, C) e “spiega” alla funzione show-menu cosa fare quando un utente sceglie una di tali opzioni. Come e` strutturata? Eccola qui:

(
  ("A" (begin
      (println "Hai premuto <A>")
    );;begin
  )
  ("B" (begin
      (println "Hai premuto <B>")
    );;begin
  );;"B"
  ("C" (begin
         (show-menu { testo_menu_secondario }
           ("SottoMenu-1" (begin
               (println "Hai premuto <SottoMenu-1>")
             );;begin
           );;"SottoMenu-1"
         );;show-menu
       );;begin
  );;"C"
)

Non spaventatevi e continuate a leggere! E` piu` semplice di quello che sembra! In sostanza, la struttura contiene dei simboli (stringhe: “A”, “B”, “SottoMenu-1″, etc…) che determinano le opzioni che un utente puo` scegliere. Ad ogni opzione e` associato un pezzo di codice. La sua caratteristica e` che puo` includere una chiamata alla show-menu, cosi` da “disegnare un sottomenu” a seguito della scelta di una determinata opzione. Questo sistema ha il vantaggio di essere molto semplice da gestire (in quanto le opzioni e il codice sono nello stesso blocco, e quindi facilmente controllabili), inoltre i vari blocchi sono “isolati” e “sigillati”, cioe` si possono spostare (per comporre i menu in modo differente) senza che il resto del programma ne risenta minimamente. In piu`, una struttura simile, permette anche di isolare dei menu usati da piu` parti (talvolta capita che un menu, in un programma, sia raggiungibile da piu` parti), estrapolandoli e memorizzandoli in variabili esterne, riducendo quindi il menu a qualcosa simile al seguente codice:

(define (esegui-blocco-A) (println "Hai premuto <A>") )
(define (esegui-blocco-B) (println "Hai premuto <B>") )

(
  ("A" (esegui-blocco-A) )
  ("B" (esegui-blocco-B) )
  ("C" (esegui-blocco-C) )
)

Dove…

(define (esegui-blocco-SM1) (println "Hai premuto <SM1>") )
(define (esegui-blocco-SM2) (println "Hai premuto <SM2>") )

(define (esegui-blocco-C)
  (show-menu
    { testo_menu_secondario }
    ("SottoMenu-1" (esegui-blocco-SM1) )
    ("SottoMenu-2" (esegui-blocco-SM2) )
  );;show-menu
)

In questa forma il sistema e` un po` piu` chiaro. Potete a questo punto comporre i menu come piu` vi piace, creando sottomenu a non finire, oppure richiamando lo stesso menu da piu` punti. Inoltre la gestione del codice e dei menu stessi risulta sempre pulita, coerente e… funzionale :-)

La funzione “show-menu”

Il “core” del sistema e` la funzione show-menu, che si occupa di leggere i menu, mostrarli a video, prendere l’input dell’utente ed elaborarlo… piu` difficile a dirsi che a farsi! Eccola qui, in tutto il suo splendore!

  ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  ;; (show-menu)
  ;;
  ;; Questa funzione e` usata per mostrare i menu
  ;; ed eseguire le opzioni relative.
  ;;
  ;; La struttura del file e` la seguente:
  ;;  (testo-menu ( (opt-1 code-1) (opt-2 code-2) (opt-3 code-3) ) )
  ;;
  ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  (define-macro (show-menu argMenu argData , localExit)
    (setq localExit 0)

    (print (dup "\n" 50))

    (do-while (= localExit 0)

      ;;
      ;; FASE 1: stampa il menu.
      ;;

      (println argMenu)

      ;;
      ;; Default menu. Necessari per navigare correttamente.
      ;;

      (println "[99    ] Indietro")
      (println "[exit  ] Esci")

      (print newline "Opzione: >> ")
      (setq userOption (upper-case (read-line)) )

      ;;
      ;; Eval user input.
      ;;

      (println (dup "/" 70))

      (if (= userOption "EXIT") (setq localExit 1) )

      (if (!= userOption "99")
        (eval (lookup userOption argData ) )
        (setq localExit 1)
      )

      ;;
      ;; Mostra "Premi enter" solo se non sto ricaricando dinamicamente il programma.
      ;; Questo permette all'utente di leggere i dati mostrati senza
      ;; tornare immediatamente al menu.
      ;;
      (if (and (!= userOption "EXIT") (= localExit 0) (!= userOption "99")) (begin
        (println (dup "/" 70))
        (print "premi ENTER per continuare..." )
        (read-line)

        (println (dup newline 10))
      ) );;if
    );;do-while

  );;showMenu

La funzione e` molto semplice. La variabile locale localExit viene impostata ad “1″ quando la funzione show-menu deve terminare (essendo quindi un sistema ricorsivo significa che verra` mostrato, se esiste, il menu precedente…). Ad ogni menu la funzione aggiunge due item: Indietro e Esci, cosi` si evita di doverli inserire in ogni sottomenu. Quando una operazione viene svolta (in base alla scelta dell’utente), la funzione mostra il messaggio “Premi un tasto per continuare…” cosi` da permettere all’utente di leggere i risultati dell’ultima scelta fatta. Che altro dire? Spero che vi sia di aiuto! Mii piacerebbe trovare soluzioni simili alternative a quella da me proposta, vi invito quindi a mandare commenti al fine di ottimizzare il sistema, oppure di renderlo ancora piu` flessibile e ancora piu` semplice da usare. A presto!





Aggiornato il CodePatterns

21 05 2008

google_translate.gif Translate To English!

Alcuni giorni fa` e` stato aggiornato il documento riguardante i Code Patterns.

Cosa sono i Code Pattern? Sono dei modi collaudati ed efficienti per risolvere dei compiti specifici. Possono per certi versi essere paragonati ai ben famosi Design Pattern, con la differenza che il Code Pattern fornisce la soluzione a diversi problemi usando qualunque strumento disponibile per newLisp, e quindi non ci si limita all’uso di codice vero e proprio. Per assurdo anche un parametro sulla linea comando dell’interprete potrebbe fornire una soluzione efficiente ad un determinato problema.

Il documento originale lo potete trovare qui: http://www.newlisp.org/download/development/CodePatterns.html

Nelle prossime settimane analizzeremo questo importante documento, uno strumento molto utile che non dovrebbe MAI mancare nella cassetta degli attrezzi di un buon programmatore (un programmatore e` colui che sviluppa programmi, mentre un buon programmatore e` colui che lo fa` avendo pero` sempre in mentre i sani principi della semplicita` di sviluppo e manutenzione del software, riusabilita`, (ri)uso di librerie consolidate e sicure, uso dei Code Pattern e Design Pattern per risolvere determinati problemi nel modo migliore possibile, etc…).

A presto!