Come diventare un mago di GIMP: una guida sugli Script-Fu (prima parte)

Creato il 29 maggio 2013 da Hugor @msdiaz61
In questo corso guidato verranno introdotti i concetti base del linguaggio Scheme, necessari per usare e creare dei comodi script Script-Fu da aggiungere ai propri.
Lo script preso in esame richiede del testo all'utente, e crea una nuova immagine perfettamente dimensionata ad esso.
Si migliorerà lo script in modo da creare dello spazio attorno al testo. In conclusione una serie di suggerimenti per aumentare le proprie conoscenze sugli Script-fu.
Nota:
Questo capitolo è stato adattato da un tutorial, scritto per la versione 1 di GIMP, di Mike Terry.
Introduzione a Scheme.
La prima regola da ricordare è che:

Ogni comando in Scheme è racchiuso tra parentesi tonde ().

La seconda nozione da sapere è che:

Il nome di una funzione/operatore è sempre il primo elemento all'interno delle parentesi mentre gli elementi successivi costituiscono i parametri della funzione.

Comunque, non tutto ciò che è racchiuso tra parentesi è una funzione; ci possono anche essere elementi di una lista, ma ciò sarà affrontato più avanti. Questa notazione è anche nota come notazione prefissa, poiché il nome della funzione viene prima di tutto. Se si conosce già la notazione prefissa o si possiede una calcolatrice che utilizza la Notazione Polacca Inversa (come ad esempio la maggior parte delle calcolatrici HP) non si dovrebbero avere problemi nel formulare espressioni in Scheme.
La terza cosa da comprendere è che:

Anche gli operatori matematici sono considerati funzioni e quindi, quando si scrivono espressioni matematiche, vengono per primi.

Questo deriva logicamente dalla notazione prefissa summenzionata.
Esempi di notazione prefissa, infissa e postfissa.
Ecco alcuni esempi che illustrano la differenza tra le notazioni prefissa, infissa, e postfissa. Supponiamo di addizionare tra di loro 1 e 23:
  • Notazione prefissa: + 1 23 (la maniera richiesta da Scheme)
  • Notazione infissa: 1 + 23 (come siamo abituati a scrivere)
  • Notazione postfissa: 1 3 + (alla maniera di molte calcolatrici HP)
Ora mettamo in pratica quanto detto sopra. Avviare GIMP, se non è già pronto, e scegliere Filtri → Script-Fu → Console. Verrà mostrata la finestra della console Script-Fu che consente di lavorare interattivamente in Scheme:
Nella parte inferiore della finestra c'è un'area di testo denominata Comando corrente. In quest'area si possono provare interattivamente semplici comandi Scheme. Per iniziare gradualmente sommiamo alcuni numeri:
(+ 3 5)


Dopo aver digitato quanto sopra e aver premuto Invio si otterrà la risposta attesa di 8 al centro della finestra.

Uso della console Script-fu.

Ora, cosa fare se si vogliono sommare più numeri? La funzione «+» può prendere due o più argomenti quindi non dovrebbero esserci problemi:

(+ 3 5 6)

Si ottiene la risposta attesa di 14.

Finora tutto ok, se si digita una istruzione Scheme questa viene immediatamente eseguita nella finestra della console Script-Fu. Ora alcuni avvertimenti....

Attenzione alle parentesi superflue.

Spesso si è abituati ad utilizzare parentesi aggiuntive ogni volta che se ne ha bisogno, come quando si scrivono complesse espressioni matematiche e si vogliono separare le parti per renderle più chiare. In Scheme, bisogna prestare attenzione a non introdurre queste parentesi extra in maniera errata. Per esempio si supponga di voler sommare 3 al risultato dell'addizione di 5 e 6:

3 + (5 + 6) + 7 = ?

Sapendo che l'operatore + può prendere una lista di numeri da sommare si potrebbe essere tentati di trasformare quanto sopra in:

(+ 3 (5 6) 7)

Tuttavia questo non è il modo corretto, si ricordi che ogni istruzione in Scheme inizia e termina con una parentesi quindi l'interprete Scheme penserà che si sta cercando di chiamare una funzione denominata «5» nel secondo gruppo di parentesi piuttosto che sommare quei numeri prima di aggiungerli a 3.

Il modo corretto di scrivere l'istruzione di cui sopra è:

(+ 3 (+ 5 6) 7)

Prestare attenzione alla corretta spaziatura.

Se si conoscono altri linguaggi di programmazione come C/C++, Perl o Java, si dovrebbe sapere che non sono necessari spazi tra gli operatori matematici per avere delle espressioni matematiche ben formate:

        3+5, 3 +5, 3+ 5
      
Queste sono tutte accettate dai compilatori C/C++, Perl e Java. Lo stesso non vale per Scheme. È obbligatorio avere uno spazio dopo un operatore matematico (o dopo ogni nome di funzione o operatore) per far sì che sia interpretato correttamente dall'interprete Scheme.

Si consiglia di fare pratica con semplici equazioni matematiche nella console di Script-Fu per acquisire dimestichezza con questi concetti iniziali.

Variabili e funzioni.

Ora che si sa che ogni istruzione Scheme va racchiusa tra parentesi e che il nome della funzione/operatore viene per primo si deve conoscere come creare ed usale le variabili e come creare ed invocare le funzioni. Si inizia con le variabili.

Dichiarare le variabili.

Anche se ci sono un paio di metodi diversi per dichiarare le variabili, il metodo preferito è quello di utilizzare il costrutto let*. Se si conoscono altri linguaggi di programmazione si noterà che questo costrutto equivale alla dichiarazione di una lista di variabili locali e di un intervallo di visibilità in cui esse sono utilizzabili. Ad esempio per dichiarare due variabili, a e b, inizializzate rispettivamente a 1 e 2 si scrive:

        (let*
           (
              (a 1)
              (b 2)
           )
           (+ a b)
        )
      
oppure su una sola linea
(let* ( (a 1) (b 2) ) (+ a b) )

Nota:


Se si sta utilizzando la finestra della console è necessario mettere tutto ciò su una singola riga. In generale tuttavia si potrebbe voler adottare una forma di indentazione per rendere i propri script più leggibili. Si approfondirà quest'argomento nel capitolo dedicato agli spazi bianchi.

Questo dichiara due variabili, a e b, le inizializza poi stampa la somma delle due variabili.

Cos'è una variabile locale?

Si noterà che l'addizione (+ a b) è stata scritta all'interno delle parentesi dell'espressione let* e non dopo di essa.

Ciò perché l'istruzione let* definisce un'area nello script in cui le variabili dichiarate sono utilizzabili; se si digita l'istruzione (+ a b) dopo l'istruzione (let* ...) si ottiene un errore poiché le variabili dichiarate sono valide unicamente nel contesto dell'istruzione let*, sono quelle che i programmatori chiamano variabili locali.

La sintassi generale di let*

La forma generale dell'istruzione let* è:

        (let* ( variabili )
          espressioni )
      
dove variabili sono dichiarate all'interno delle parentesi, per esempio (a 2), e nelle espressioni vi può essere una qualsiasi espressione valida in Scheme. Si ricordi che le variabili qui dichiarate sono valide solo all'interno dell'istruzione let*, dato che sono variabili locali.

Spazi bianchi.

Si è menzionato precedentemente che si può utilizzare l'indentazione per rendere più chiari ed organizzare meglio i propri script. È una buona pratica da adottare e non crea problemi in Scheme -- gli spazi bianchi sono ignorati dall'interprete Scheme -- può quindi essere adottata per organizzare il codice all'interno di uno script. Tuttavia se si lavora nella finestra della console di Script-fu si deve immettere una intera espressione su un unica linea; cioè tutto ciò che sta tra la parentesi iniziale e finale di una espressione, nella finestra della console di Script-Fu deve stare su un'unica riga.

Assegnare un nuovo valore ad una variabile.

Una volta che si è inizializzata una variabile, può essere necessario doverne cambiare il valore più avanti nello script. In tal caso si usi l'istruzione set! per cambiare il valore della variabile:

        (let* ( (theNum 10) ) (set! theNum (+ theNum theNum)) )
      

Si indovini cosa fa l'istruzione riportata sopra poi la si immetta nella finestra della console Script-Fu.

Nota:


La «\» indica che non c'è un'interruzione di riga. La si ignori (non la si digiti nella console Script-Fu e non si prema Invio) e si continui con la linea successiva.

Funzioni.

Ora che si è appreso l'uso delle variabili si proceda con le funzioni. Le funzioni si dichiarano con la seguente sintassi:

        (define 
           (
              nome
              elenco parametri 
           )
           espressioni 
        )
      

dove name è il nome assegnato alla funzione, param-list è una lista di parametri separati da spazi e expressions è una serie di espressioni che la funzione esegue quando viene chiamata. Ad esempio:

(define (AddXY inX inY) (+ inX inY) )

AddXY è il nome della funzione e inX e inY sono le variabili. Questa funzione prende i suoi due parametri e li somma.

Se si è programmato in altri linguaggi imperativi (come C/C++, Java, Pascal, ecc.), si può notare come manchino un paio di cose a questa definizione di funzione rispetto agli altri linguaggi di programmazione.

  • Per prima cosa si noti che i parametri non hanno un «tipoZ (non si devono dichiarare come stringhe o interi, ecc.). Scheme »
  • Secondo, si noti che non ci si deve preoccupare di «ritornare» il risultato della funzione -- l'ultima istruzione è il valore «ritornato» al chiamante della funzione. Si immetta la funzione nella console e poi si provi qualcosa del tipo:
    (AddXY (AddXY 5 6) 4)
    
Liste, liste e ancora liste.

Abbiamo fatto pratica con le variabili e le funzioni, ora si entra nella palude fangosa delle liste di Scheme.


Definire una lista.
Prima di approfondire le liste è necessario comprendere la differenza tra valori atomici e liste.
Abbiamo già visto i valori atomici quando abbiamo inizializzato le variabili nella sessione precedente. Un valore atomico è un valore singolo. Ad esempio possiamo assegnare alla variabile «x»" il singolo valore 8 nell'istruzione seguente:

(let* ( (x 8) ) x)

(abbiamo aggiunto l'espressione x alla fine per stampare il valore assegnato a x; normalmente non si dovrebbe averne bisogno. Si noti come let* operi come una funzione: il valore dell'ultima istruzione è il valore restituito)
Una variabile può anche riferirsi ad una lista di valori piuttosto che a un singolo valore. Per assegnare alla variabile x la lista di valori 1, 3, 5 si digiti:
(let* ( (x '(1 3 5))) x)

Si provi a digitare entrambe le istruzioni nella console Script-fu e si osservino le risposte. Quando si digita la prima istruzione si ottiene semplicmente il risultato:
8

Mentre se si digita l'altra istruzione si ottiene il seguente risultato:
(1 3 5)

Quando si ottiene il valore 8 l'interprete sta informando che x contiene il valore atomico 8 mentre quando si ottiene (1 3 5) sta informando che x contiene non un valore singolo bensì una lista di valori. Si noti che non ci sono virgole nella dichiarazione o assegnamento della lista, tantomeno nel risultato stampato.

La sintassi per definire una lista è:

'(a b c)

dove a, b, e c sono letterali. Si usa l'apostrofo (') per indicare che ciò che segue nelle parentesi è una lista di valori letterali piuttosto che una funzione o un'espressione.

Una lista vuota può essere definita come segue:

'()

o semplicemente:
()

Le liste possono contenere valori atomici così come altre liste:
(let*
   (
        (x
           '("GIMP" (1 2 3) ("è" ("grande" () ) ) )
        )
    )
    x
)
      

Si noti che dopo il primo apostrofo non vi è più bisogno di utilizzare un apostrofo per definire le liste interne. Si provi a copiare l'istruzione nella console Script-Fu e ad eseguirla per vedere cosa restituisce.
Si noti come il risultato restituito non è una lista di valori atomici singoli ma piuttosto è una lista di letterali ("GIMP"), la lista (1 2 3), ecc.

Come concepire le liste.


È utile pensare alle liste come composte di una «testa» e una «coda». La testa è l'elemento iniziale della lista, la coda è la parte restante. Si capirà l'importanza di questo concetto quando si parlerà di come si compongono le liste e come accedere agli elementi di una lista.
Creazione di liste attraverso la concatenazione (la funzione Cons)
Una delle funzioni più comuni che si incontrano è la funzione cons. Prende un valore e lo mette in testa al suo secondo argomento, una lista. Nel capitolo precedente si è suggerito di pensare una lista come composta da un elemento (la testa) è la parte restante (la coda), questo è esattamente il comportamento della funzione cons: aggiunge un elemento in testa alla lista. Si potrebbe creare una lista come segue:

(cons 1 '(2 3 4) )

Il risultato è la lista (1 2 3 4).


Si può anche creare una lista con un solo elemento:
(cons 1 () )

Si possono utilizzare variabili dichiarate in precedenza al posto di qualunque letterale come ci si aspetta.
Definizione di una lista usando la funzione list.

Per definire una lista composta da letterali oppure da variabili precedentemente dichiarate si utilizza la funzione list:


(list 5 4 3 a b c)

Ciò costruirà e resituirà una lista contenente i valori mantenuti dalle variabili a, b e c. Ad esempio:
        (let*  (
                  (a 1)
                  (b 2)
                  (c 3)
               )

               (list 5 4 3 a b c)
        )
      

Questo codice crea la lista (5 4 3 1 2 3).

Accedere ai valori contenuti in una lista.

Per accedere ai valori in una lista usare le funzioni car e cdr, che restituiscono rispettivamente il primo elemento della lista e la porzione restante. Queste funzioni spezzano la lista nel costrutto testa::coda precedentemente menzionato.

La funzione car.


car restituisce il primo elemento della lista (la testa della lista). La lista deve essere non-nulla. L'istruzione seguente restituisce il primo elemento della lista:

(car '("primo" 2 "secondo"))"
che è:

 "primo"

La funzione cdr.

cdr restituisce la parte restante della lista dopo il primo elemento (la coda della lista). Se vi è un solo elemento nella lista, restituisce una lista vuota.

(cdr '("primo" 2 "secondo"))
 restituisce:
(2 "terzo")
 mentre l'istruzione seguente:

  (cdr '("uno e solo"))

  
restituisce:

 ()


Accedere ad altri elementi di una lista.

  Bene, si è ora in grado di ottenere il primo elemento di una lista così come la parte restante ma come si accede agli altri elementi di una lista? Esistono parecchie funzioni di "convenienza" per accedere alla testa della testa (caadr) o analogamente alla coda di una lista (cddr), ecc.

  
La convenzione sui nomi di base è semplice: le a e le d rappresentano le teste e le code quindi

   (car (cdr (car x) ) )

  si potrebbe scrivere come:

  
(cadar x)

Per impratichirsi con le funzioni di accesso alle liste si provi a digitare quanto segue (su di un'unica riga se si utilizza la console), si utilizzino differenti varianti di car e cdr per accedere ai differenti elementi della lista:

  (let* ( (x '( (1 2 (3 4 5) 6) 7 8 (9 10) ) ) ) ; metti il tuo codice car/cdr qui )

  
Si provi ad accedere al numero 3 nella lista utilizzando solo due chiamate a funzione. Se si è in grado di farlo si è sulla buona strada per diventare un maestro di Script-Fu!


Nota:


In Scheme, un punto e virgola (;) indica un commento. Il segno stesso e quanto segue sulla stessa linea sono ignorati dall'interprete quindi si può utilizzare il punto e virgola per aggiungere commenti utili a rinfrescare la memoria quando si riprende in mano uno script a distanza di tempo.  

Ricerca personalizzata



Se ti è piaciuto l'articolo , iscriviti al feed cliccando sull'immagine sottostante per tenerti sempre aggiornato sui nuovi contenuti del blog:


Potrebbero interessarti anche :

Possono interessarti anche questi articoli :