; OGGETTI CONNETTIBILI in LISP (crivello di Eratostene)
; Parte per il debugging su video
(defconstant Debug 1) ; 0=no debug; 1=si' debug
(defun debug1 (msg)
(cond ((= Debug 1) (print msg)) ))
(defun debug2 (m1 m2)
(cond ((= Debug 1) (prin1 m1)(print m2)) ))
(defun debug3 (m1 m2 m3)
(cond ((= Debug 1) (prin1 m1)(prin1 m2)(print m3)) ))
(defun debug4 (m1 m2 m3 m4)
(cond ((= Debug 1) (prin1 m1)(prin1 m2)(prin1 m3)(print m4)) ))
; PRIMITIVE SUGLI STREAM:
;Costruzione; avendo in ingresso il primo elemento
; e la funzione generatrice (una chiusura)
(defun ConsStream (PrimoEl FunGen) (cons PrimoEl FunGen))
; Rende l'elemento in testa allo stream
(defun Head (Stream) (car Stream))
; Rende lo stream ottenuto rimuovendo l'elemento in testa
(defun Tail (Stream) (funcall (cdr Stream)))
; Dice se uno stream e' vuoto
(defun EmptyS (Stream) (null Stream))
; Rende (sempre) lo stream vuoto
(setq EmptyStream nil)
; UTILIZZO DEGLI STREAM
; GENERATORE: crea uno stream di interi
(defun IntStream (n)
(debug2 'generazione_ n)
(ConsStream n
(lambda () (IntStream (+ 1 n)))
))
; idem ma e' uno stream limitato
(defun IntStreamLimit (n max)
(debug2 'generazione_ n)
(cond ((eq n max) EmptyStream)
( t (ConsStream n
(lambda() (IntStreamLimit (+ 1 n) max))))
))
; STAMPA: stampa uno a uno tutti gli elementi di uno stream
(defun StampaStream (S)
(cond ((EmptyS S) EmptyStream)
( t (print (Head S))(StampaStream (Tail S)) )
))
; FILTRO: lascia passare o arresta un numero a seconda
; che verifichi il predicato Pred
(defun Filtro (S Pred)
(cond ( (EmptyS S) EmptyStream)
((funcall Pred (Head S)) (debug4 'filtro_ (funcall Pred -1) '_passa_ (Head S))
(ConsStream (Head S)
(lambda () (Filtro (Tail S) Pred))))
( t (debug4 'filtro_ (funcall Pred -1) '_blocca_ (Head S))
(Filtro (Tail S) Pred))
))
; ACCUMULATORE: esegue l'operazione Oper (con elemento neutro ElNeutro) su
; tutti gli elementi di uno stream
(defun Accum (S ElNeutro Oper)
(cond ((EmptyS S) ElNeutro)
( t (debug2 'accumulatore_usa_ (Head S))
(funcall Oper (Head S) (Accum (Tail S) ElNeutro Oper)))
))
; LIMITATORE: limita il numero di elementi resi da uno stream
(defun Limita (S Conta MaxConta)
(cond ((eq Conta MaxConta) EmptyStream)
( t (ConsStream (Head S)
(lambda () (Limita (Tail S) (+ Conta 1) MaxConta))) )
))
; TRASFORMA: rende uno stream costituito dagli elementi dello stream
; dato a cui e' applicata la funzione Fun
(defun Trasforma (S Fun)
(cond ((EmptyS S) EmptyStream)
( t (ConsStream (funcall Fun (Head S))
(lambda () (Trasforma (Tail S) Fun))))
))
; OPERAZIONI "UTILI":
; Operazione di "non divisibilita'" tra due numeri
; (e' usata per il crivello di Eratostane)
(defun NoDivisibili (x y)
(cond ((/= x -1) (/= 0 (rem x y)))
( t y) ; rende il valore del divisore per x=-1
))
; Operazione "un numero e' pari"
(defun Pari (x)
(= 0 (rem x 2)))
; Operazioni "dimostrative" per trasformazione
(defun PiuUno (x) (+ x 1) )
(defun PerDue (x) (* x 2) )
(defun Somma (x y) (+ x y) )
; SETACCIO per Eratostane: rende uno stream con i numeri primi
(defun Sift (S)
(cond ((EmptyS S) S)
( t (debug2 'Nuovo_Numero_Primo_Trovato_ (Head S))
(ConsStream (Head S)
(lambda () (Sift (Filtro (Tail S) (lambda (x) (NoDivisibili x (Head S))) ))) )
)
))
; Stampa i numeri primi tra 2 e 19
(defun prova0 () (StampaStream (Sift (IntStreamLimit 2 20))))
; Stampa i primi 3 numeri primi
(defun prova1 () (StampaStream (Limita (Sift (IntStream 2)) 0 3)))
; Stampa i primi 5 numeri primi
(defun prova2 () (StampaStream (Limita (Sift (IntStream 2)) 0 5)))
; Stampa i primi 31 numeri primi
(defun prova3 () (StampaStream (Limita (Sift (IntStream 2)) 0 31)))
; Stampa i numeri pari tra 2 e 5
(defun prova4 () (StampaStream (Filtro (IntStreamLimit 2 6) (lambda (x) (Pari x))) ))
; Stampa l'intervallo 2-4 sommando uno a ogni elemento (cioe' intrvallo 3-5)
(defun prova5 () (StampaStream (Trasforma (IntStreamLimit 2 8) (lambda (x) (PiuUno x)))))
; Stampa l'intervallo 2-4 moltiplicando per due ogni elemento
(defun prova6 () (StampaStream (Trasforma (IntStreamLimit 2 8) (lambda (x) (PerDue x)))))
; Stampa la somma dei numeri tra 1 e 6
(defun prova7 () (Accum (IntStreamLimit 1 7) 0 (lambda (x y) (Somma x y))))
; Idem (versione alternativa)
(defun prova8 () (Accum (IntStreamLimit 1 7) 0 (lambda (x y) (+ x y))))
; Stampa la somma dei numeri tra 1 e 19
(defun prova9 () (Accum (IntStreamLimit 1 20) 0 (lambda (x y) (+ x y))))
; Stampa la somma dei primi 4 numeri primi
(defun prova10() (Accum (Limita (Sift (IntStream 2)) 0 4) 0 (lambda (x y) (+ x y))))
; Stampa la somma dei primi 20 numeri primi
(defun prova11() (Accum (Limita (Sift (IntStream 2)) 0 20) 0 (lambda (x y) (+ x y))))