cg-Cad

Lisp »Tips 'n Tricks »Uso di Foreach (I) »(II)

Foreach valuta tutte le espressioni dei membri di una lista:
(foreach nome lista istruzioni).
La funzione esamina la lista, assegna ogni elemento della lista a nome e valuta tutte le istruzioni al suo interno.

Ad esempio questo lisp legge con (foreach) il contenuto di una lista e controlla se l'elemento nome è un numero reale o intero con la funzione (numberp elem).
Numberp restituisce T se elem è un numero, altrimenti restituisce nil.
Se non è (if not) vero (T) allora stampa (princ) l'elemento della lista (nome).

(defun for ()
 (setq lista (list "io" 0 -1 2 -3 7.5 " e " -0.5 "la talpa" 13))
 (foreach nome lista 
  (if (not (numberp nome))
   (princ nome)
  )
 )
 (princ)
)

Command: (for)
io e la talpa

Lupo Alberto © SilverIn un certo qual modo la funzione (foreach) può sostituire l'istruzione for presente in altri linguaggi di programmazione.
Ecco un esempio, prima in linguaggio Pascal e poi tradotto in Lisp.

"Il programma (graph.pas) mette in diagramma una funzione reale f(X) con l'asse X che si sviluppa verticalmente, ed appone un asterisco nelle posizioni corrispondenti alle coordinate.
La posizione dell'asterisco si ottiene calcolando Y=f(X), moltiplicando per un fattore di scala, arrotondando il prodotto al successivo numero intero e poi aggiungendo una costante e lasciando che l'asterisco sia preceduto da tanti spazi bianchi quanto è il valore del prodotto arrotondato suddetto" (op. cit)

graph.pas

(* 
  Graph.pas
  Generate graphic representation of the function:
  f(x) = exp(-x)*sin(2*pi*x)

   Dal testo: 'Manuale del Pascal', K. Jensen, N. Wirth 
*)

program Graph(Output);

const
   XLines=16;
   Scale=32;
   ZeroY=34;
   XLimit=32;

var
   Delta: Real;
   TwoPi: Real;
   X,Y: Real;
   Point: Integer;
   YPosition: Integer;

begin
   Delta:=1/Xlines;
   TwoPi:=8*ArcTan(1.0);

   for Point:=0 to XLimit do
      begin
         X := Delta * Point;
         Y := Exp(-X) * Sin(TwoPi*X);
         YPosition := Round(Scale*Y) + ZeroY;
         repeat
            Write(Output, ' ');
            YPosition := YPosition - 1
         until YPosition = 0;
         Writeln(Output, '*')
      end
end.

graph.lsp

;| 
  Graph.lsp by Claudio Piccini (29/02/2004)
  www.cg-cad.com
  
  Salva su file graph.txt il diagramma della funzione:
  f(x) = exp(-x)*sin(2*pi*x)

  Basato su:
  Program 4.7 - "Manuale del Pascal",
                K. Jensen, N.Wirth
|;

(defun c:graph ( )

 (setq Xlines 16)
 (setq Scale 32)
 (setq ZeroY 34)
 (setq Delta (/ 1.0 Xlines))

 (setq i 0)
 (while (< i 33)
  (setq Xlimit (append Xlimit (list i)))
  (setq i (1+ i))
 )

 (setq nomeDir (getvar "dwgprefix"))
 (setq nf (strcat nomeDir "graph.txt"))
 (setq f1 (open nf "w"))

 (foreach Point Xlimit 
  (setq x (* Delta Point)) 
  (setq y (* 
            (exp (* x -1))
            (sin (* 2 pi x))
          )
  )
  (if (>= (* Scale y) 0)
   (setq Round (fix (+ (* Scale y) 0.5)))
   (setq Round (fix (- (* Scale y) 0.5)))
  )
  (setq YPosition (+ Round ZeroY))
  (setq spazio "")
  (repeat YPosition
   (setq spazio (strcat spazio " ")) 
   (setq YPosition (- YPosition 1))
  )
  (setq asterisco (strcat spazio "*"))
  (write-line asterisco f1)
 )

 (close f1)

)
;;;eof

Test del lisp

                                  *
                                              *
                                                      *
                                                           *
                                                           *
                                                        *
                                                  *
                                          *
                                  *
                           *
                      *
                   *
                   *
                     *
                         *
                             *
                                  *
                                      *
                                         *
                                           *
                                           *
                                          *
                                        *
                                     *
                                  *
                               *
                              *
                             *
                            *
                             *
                               *
                                *
                                  *

Lupo Alberto © SilverIn Autolisp non esiste la funzione round(R).

Che cos'è la funzione round(R)?
Con R numero reale il risultato di round(R) è un numero intero arrotondato, cioè round(R) equivale a trunc(R + 0.5) se R>=0 e a trunc(R - 0.5) se R<0.

Che cos'è la funzione trunc(R)?
Con R numero reale il risultato di trunc(R) è un numero intero troncato, ad esempio trunc(3.7)=3 e trunc(-3.7)=-3.

Esiste in Autolisp una funzione uguale a trunc? Sì, è la funzione (fix)

Quindi l'istruzione in Pascal:
YPosition := Round(Scale*Y) + ZeroY;

Si traduce così in Autolisp:
(if (>= (* Scale y) 0)
(setq Round (fix (+ (* Scale y) 0.5)))
(setq Round (fix (- (* Scale y) 0.5)))
)
(setq YPosition (+ Round ZeroY))

Infine notare che l'istruzione in Pascal:
Delta:=1/Xlines;

Cambia così in Autolisp:
(setq Delta (/ 1.0 Xlines))

Questo perché Xlines è dichiarato come const e Delta come variabile Real; in Autolisp non esiste la distinzione tra l'intestazione e il blocco del programma.
Ad esempio con questo sorgente pascal:

program Prova(Output);

(* intestazione del programma *)
const
x = 12;

var
y: Real;

(* blocco del programma *)
begin
y := 1/x;
Writeln('Y=', y)
end.


Si ottiene questo output: Y= 8.3333333333E-02

Invece in Autolisp:
Command: (setq x 12)
12
Command: (setq y (/ 1 x))
0
Quindi si deve forzare in questo modo:
Command: (setq y (/ 1.0 x))
0.0833333

Per ultimo (ma non ultimo) notare che la funzione pascal Exp(-X) si trasforma nell'istruzione in autolisp (exp (* x -1))

Lupo Alberto © Silver

Lisp »Tips 'n Tricks

Ultimo Aggiornamento_Last Update: 29 Febbraio 2004