venerdì 8 ottobre 2004





 I t e r a z i o n e    " p e r  v e r o "      ( ciclo   " w h i l e "  ) 


Nell'algoritmo per l'implementazione del costrutto VECTOR abbiamo visto che uno stesso gruppo  I  di istruzioni viene ripetuto ciclicamente per tutto il tempo in cui una condizione  C  viene trovata vera. Questo ciclo è detto "iterazione per vero" oppure "iterazione con uscita per falso". Il diagramma è :







       

:
:
_|_
/ falso
*->-/ C --->*
| / |
| _ _/ |
| vero| |
| __|__ |
| | | |
*-<-| I | |
|_____| |
|
*<------*
|
:
:
un altro possibile diagramma, perfettamente equivalente, è :
:
:
|<----------*
_|_ |
/ vero |
/ C --->* |
/ | |
_ _/ __|__ ^
| | ||
falso | I ||
| |_____||
: | |
: *->-*


 








La versione testuale di tale ciclo iterativo è :

mentre  C  esegui  I

(   while   C  do  I   )


 


La naturale definizione sarebbe teoricamente:

   (1) mentre(C,I) := IF( C , mentre(C,I) , "fine ciclo" )

Però Derive quando valuta una funzione definita dall'utente per prima cosa cerca di valutarne gli argomenti (ossia gli input; in questo caso C e I) e solo dopo applica la definizione della funzione; pertanto la valutazione della espressione mentre(C,I) di sopra verrebbe effettuata con i valori trovati per C e per I la prima volta che tale valutazione è eseguita e, se C risulta vera si entra in un loop senza uscita, mentre se C risulta falsa si accede subito
alla stringa "fine ciclo".

Esiste però un operatore (operatore "apice", con simbolo ' ) , detto operatore di "citazione" ("quote operator") o di "differimento di valutazione", che anteposto a una espressione produce un'espressione "citante" la cui valutazione è l'espressione "citata". Ad esempio se, dopo aver posto x := 4 , valutiamo (col pulsante "=") x+2 , il risutato della valutazione è 6 , mentre se valutiamo '(x+2) oppure 'x + 2 il risultato è x+2, in quanto nel primo caso rimane inalterata (quindi non valutata) l'intera espressione (x+2) , mentre nel secondo rimane non valutata la variabile x (che è un tipo elementare, o "atomico", di espressione).

Nelle espressioni funzionali con argomenti "apiciati" (ossia she sono espressioni sottoposte all'operatore  ' ) Derive non effettua la preventiva valutazione di tali argomenti.

Perciò potremmo usare nell'espressione mentre(C,I) espressioni con apici; ad esempio: C := '(x<=10) e I := '[v := APPEND(v, [x^2]); x := x + 1] e in tal caso Derive non valutando C e I produce internamente, tramite la definizione di sopra


     (2)     IF( '(x<=10) , mentre('(x<=10),'[v := APPEND(v, [x^2]); x := x + 1]) , "fine ciclo" )
poi semplifica ciò che può valutare e produce:
    (2bis)   IF( x<=10 , mentre(x<=10,[v := APPEND(v, [x^2]); x := x + 1]) , "fine ciclo" )
quindi non effettua alcun ciclo; e, del resto, se continuassimo con la valutazione della espressione (2) ricadremmo nel loop senza termine (dal momento che adesso gli apici non ci sono più).

Esiste però un modo per costringere Derive a valutare direttamente un'espressione con apice. Uno possibile e definire le seguenti funzioni :

     testa(L) := L SUB 1

     valuta(E) := testa([E])

La prima prende il primo elemento (detto "la testa") di una lista, ad esempio:

                           testa([1,2,3,4])   viene valutato :    1

La seconda prende una espressione E, la valuta, usa il risultato r per costruire una lista [r] costituita solo da tale risultato e poi valuta testa([r]), per la quale cosa valuta r nell'espressione [r] per poi applicare la definizione della funzione testa.

Pertanto se partiamo dall'espressione (un numero è una particolare espressione, costante) 5 l'espressione valuta(5) viene valutata seguendo i seguenti passi :
- si valuta il 5 e il risultato è ... 5 ;
- si segue la definizione della funzione "valuta" e quindi si ottiene testa([5]) ;
- si valuta l'input ("argomento") presente nell'espressione testa([5]) , ossia [5], e si ottiene testa([5]) ;
- si applica la definizione della funzione "testa" pervenendo a [5] SUB 1, ossia 5.

Proviamo, dopo aver gia definito x:=4 come già fatto, a valutare l'espressione
valuta(x) seguendo gli stessi passi di sopra :
- si valuta x e il risultato è 4 ;
- si segue la definizione della funzione "valuta" e quindi si ottiene testa([4]) ;
- si valuta l'input ("argomento") presente nell'espressione testa([4]) , ossia [4], e si ottiene testa([4]) ;
- si applica la definizione della funzione "testa" pervenendo a [4] SUB 1, ossia 4.

Proviamo adesso a valutare l'espressione valuta('x) :
- non si valuta subito l'argomento 'x (in quanto è sotto la "protezione" dell'apice);
- si segue la definizione della funzione "valuta" e quindi si ottiene testa(['x]) ;
- si valuta l'input ("argomento") presente nell'espressione testa(['x]) , ossia ['x], e si ottiene testa([x]) ;
- si applica la definizione della funzione "testa" pervenendo a [x] SUB 1, ossia x ;
- l'ultima fase della valutazione di una funzione è la semplificazione, perciò l'espressione x viene valutata 4 .

Come vediamo, così facendo partiamo da 'x e otteniamo non x ma il valore 4 della variabile x

Altro esempio: valutiamo l'espressione (apiciata) '(x>0) :
- non si valuta '(x>0) ;
- si segue la definizione della funzione "valuta" e quindi si ottiene testa(['(x>0)]) ;
- si valuta (semplifica) tale ultima espressione, ottenendo testa([x>0]) ;
- si valuta testa([x>0]), quindi si provvede anzitutto a valutare [x>0] in [true] ;
- si applica la definizione della funzione "testa" pervenendo a [true] SUB 1, ossia true.

Un'altra osservazione sulla valutazione delle espressioni: se si è definita una funzione di due argomenti, ad esempio

        potenza(base,esponente) := base ^ esponente

e la si applica a più argomenti di quelli usati nella definizione, ad esempio :

     (3)     potenza(3,2,x:=3)

la definizione usa solo i primi argomenti che effettivamente le servono in base alla definizione pur però valutando tutti gli argomenti presenti in (3). Quindi, valutando la (3) si ottiene l'atteso 9 (ossia 3^2), ma ... x è diventato 3
(ricordiamoci che prima era stato definito come 4).

Applichiamo quanto visto alla definizione della funzione "mentre".

Definiamo:
                    mentre(C,I) := IF( valuta(C) , mentre( C , I , valuta(I) ) , "fine ciclo" )

  Poniamo preliminarmente le due definizioni ("assegnamenti")   x:=0    e   v:=[ ]   e supponiamo che   C  sia  '(x <= 10)   e che  I  sia  '[v := APPEND(v, [x^2]); x := x + 1].
In quanto apiciate, C e I vengono passate non valutate, ma poi IF determina la valutazione dell'espressione valuta(C), la quale risulta true per cui si procede a valutare l'espressione mentre(C,I,valuta(I)), il che comporta come effetto collaterale la valutazione dell'espressione valuta(I) ( cosa che fa eseguire I stessa ), prima di passare alla esecuzione di mentre(C,I), il che fa ricominciare il tutto, ma dopo la valutazione di I  ( che ha modificato il valore della variabile x )


 







In definitiva:

digitiamo in Derive (riga di editing):



testa(L) := L SUB 1

valuta(E) := testa([E])

mentre(C,I) := IF(valuta(C),mentre(C,I,valuta(I)),"fine ciclo")


Verifichiamo il funzionamento digitando, e poi valutando :


[v := []; x := 0; mentre('x <= 10, '[v := APPEND(v, [x^2]); x := x + 1]); v; x]

l'output sarà :







 

¦ [] ¦
¦ ¦
¦ 0 ¦
¦ ¦
¦ fine ciclo ¦
¦ ¦
¦ [0, 1, 4, 9, 16, 25, 36, 49, 64, 81, 100] ¦
¦ ¦
¦ 11 ¦

 































































































2 commenti:

  1. Lo scopo di questo "post" è quello di mostrare come il ciclo iterativo per vero è definibile solo con l'uso di IF e della "ricorsione in coda".
    Volendo invece approfittare del costrutto ITERATE di Derive possiamo usare le seguenti due definizioni:

    ripeti(a) := ITERATE(a, x__)

    mentre(C, I) := ripeti(IF(C,I, "stop"))

    Volendo usare la funzione "ripeti" anche un numero prefissato di volte, possiamo usare la definizione alternativa:

    ripeti(a, n) := ITERATE(a, x__, "", n)

    A proposito di ITERATE, possiamo definire la funzione "valuta" non usando le testa di una lista ma come:

    valuta(t) := ITERATE(x__, x__, t, 1)

    RispondiElimina
  2. Un'applicazione di esempio:
    poligoni regolari tracciati nello stile del LOGO.

    il testo da digitare in derive è:

    testa(t):=t SUB 1

    val(t):=testa([t])

    mentre(c,i):=IF(val(c),mentre(c,i,val(i)),"ciclo eseguito")

    output(u):=u SUB DIMENSION(u) SUB 1

    poligono(n,L):=output([[[a:=0,p_:=[0,0],i_:=1,a_:=2*pi/n,v_:=[p_]]],~
    [mentre('(i_<=n),'[[p_:=p_+[COS(a),SIN(a)]*L],[v_:=APPEND(v_,[p_])],[a:=a+a_],[i_:=i_+1]])],[v_]])

    poligono(60,0.1)

    valuta e poi rappresenta l'ultima espressione

    RispondiElimina