-
X-Received: by 10.140.34.14 with SMTP id k14mr5032qgk.8.1415540051226; Sun, 09 Nov
2014 05:34:11 -0800 (PST)
X-Received: by 10.140.34.14 with SMTP id k14mr5032qgk.8.1415540051226; Sun, 09 Nov
2014 05:34:11 -0800 (PST)
Path: news-archive.icm.edu.pl!news.icm.edu.pl!newsfeed.pionier.net.pl!news.glorb.com!
h15no953152igd.0!news-out.google.com!u1ni1qah.0!nntp.google.com!i13no328782qae.
0!postnews.google.com!glegroupsg2000goo.googlegroups.com!not-for-mail
Newsgroups: pl.comp.programming
Date: Sun, 9 Nov 2014 05:34:11 -0800 (PST)
In-Reply-To: <f...@g...com>
Complaints-To: g...@g...com
Injection-Info: glegroupsg2000goo.googlegroups.com; posting-host=46.186.78.6;
posting-account=f7iIKQoAAAAkDKpUafc-4IXhmRAzdB5r
NNTP-Posting-Host: 46.186.78.6
References: <c...@g...com>
<f...@g...com>
User-Agent: G2/1.0
MIME-Version: 1.0
Message-ID: <6...@g...com>
Subject: Re: Makra w jezyku Scheme
From: g...@g...com
Injection-Date: Sun, 09 Nov 2014 13:34:11 +0000
Content-Type: text/plain; charset=ISO-8859-1
Xref: news-archive.icm.edu.pl pl.comp.programming:206866
[ ukryj nagłówki ]* POTRZEBA NOWYCH FORM SPECJALNYCH
** UWAGI WSTEPNE
Dotychczas omowilem zaledwie 6 podstawowych form specjalnych potrzebnych
do tego, zeby budowac zlozone programy. Brakuje tutaj jednak wielu rodzajow
wyrazen, ktore znamy z innych jezykow programowania, takich jak mozliwosc
wprowadzania zmiennych pomocniczych w ciele funkcji, albo logicznych operatorow
koniunkcji i alternatywy (negacje moglibysmy bowiem zdefiniowac jako funkcje:
(define not (lambda (x) (if x #f #t)))).
W tym celu musielibysmy dysponowac jeszcze przynajmniej jedna forma specjalna,
pozwalajaca nam na definiowanie nowych form specjalnych. Nie powinno to byc
trudne, poniewaz -- jak sobie powiedzielismy na poczatku -- programy w lispie
sa listami symboli, wiec wystarczyloby zmodyfikowac reguly ewaluacji w taki
sposob, zeby wszystkie nowe formy specjalne byly przed wykonaniem przeksztalcane
do postaci zawierajacej wylacznie funkcje i pierwotne formy specjalne.
Taka procedura przeksztalcajaca jakies wyrazenie (liste) w inne wyrazenie
(liste) nazywana jest *makrem*. Zanim poznamy szczegoly dotyczace tego,
jak mozna definiowac makra, sprobujemy sie zastanowic, jak bysmy mogli
chciec uzywac danego wyrazenia, oraz jak moglaby wygladac nasza forma
wynikowa. Jedyne ograniczenie jest takie, ze nasza skladnia musi byc
zgodna ze skladnia lispa.
UWAGA! WSZYSTKIE MAKRA PRZEDSTAWIONE W TYM ROZDZIALE SA CZESCIA JEZYKA
SCHEME I NIE TRZEBA ICH DEFINIOWAC. GDYBY CZYTELNIK ZECHCIAL ZDEFINIOWAC
SWOJE WERSJE PONIZSZYCH FORM SPECJALNYCH, ZALECAM NADANIE IM INNYCH NAZW.
** ZMIENNE LOKALNE -- FORMA "let"
Czasem wygodnie jest przechowac dana wartosc w zmiennej pomocniczej.
: (let ((x^2 (* x x))
: (y^2 (* y y)))
: (/ (- x^2 y^2) (+ x^2 y^2)))
W tym wypadku uzylismy zmiennych lokalnych o nazwach "x^2" i "y^2"
do zapamietania wyniku obliczenia dzialan (* x x) i (* y y) (przy zalozeniu,
ze zmienne "x" i "y" sa zwiazane w kontekscie wyrazenia). W przeciwnym
razie musielibysmy dwukrotnie wyliczyc wynik mnozenia, zas glowne wyrazenie
staloby sie rozwleklejsze:
: (/ (- (* x x) (* y y)) (+ (* x x) (* y y)))
Zauwazmy, ze pozadany efekt mozemy uzyskac przy pomocy formy "lambda":
: ((lambda(x^2 y^2)(/ (- x^2 y^2) (+ x^2 y^2))) x y)
Dlatego chcielibysmy, zeby formy postaci
: (let ((nazwa wartosc) ...) cialo + ...)
byly przed ewaluacja transformowane do postaci
: ((lambda (nazwa ...) cialo + ...) wartosc ...)
** LOGICZNE SPOJNIKI "and" i "or"
Moglibysmy zdefiniowac operatory logiczne "and" i "or" jako funkcje:
: (define and2 (lambda (p q) (if p q #f)))
: (define or2 (lambda (p q) (if p p q)))
Z taka definicja sa jest jednak pewien problem: mianowicie, nasz operator
ewaluuje wsztstkie swoje argumenty, choc teoretycznie jezeli pierwszy
argument ma wartosc falszu, to moglibysmy zaniechac ewaluacji kolejnych
argumentow (taka metoda ewaluacji nosi nazwe "short-circit evaluation"
albo "McCarthy evaluation", i implementuja je wlasciwie wszystkie
wspolczesnie uzywane jezyki programowania).
Moglibysmy zatem zyczyc sobie, zeby kod
: (or p q)
byl przed wykonaniem transformowany do postaci
: (if p p q)
jednak wowczas problemem byloby to, ze wyrazenie "p" -- o ile jego wartoscia
nie bylby falsz logiczny -- byloby ewaluowane dwukrotnie. Moglibysmy temu
zapobiec transformujac nasza alternatywe do postaci
: (if p #t q)
albo, pragnac zachowac wartosc wyniku ewaluacji, przeksztalcic ja nastepujaco:
: (let ((T p)) (if T T q))
gdzie T jest symbolem niewystepujacym w q. Moglibysmy tez uogolnic operator
"or" w taki sposob, zeby mogl przyjmowac dowolnie wiele argumentow, i zeby
wyrazenia postaci
: (or p q r ...)
byly transformowane do postaci
: (let ((T p)) (if T T (or q r ...)))
Analogicznie moglibysmy oczekiwac, zeby wyrazenia postaci
: (and p q)
byly przed ewaluacja przeksztalcane do postaci
: (if p q #f)
i ogolniej, interpretowac wyrazenia
: (and p q r ...)
jako
: (if p q (and r ...))
** FORMA SPECJALNA "cond"
Wiekszosc popularnych jezykow programowania posiada specjalna konstrukcje
dla wyboru sekwencyjnego, np.
: if warunek { dzialania ... }
: else if inny_warunek { inne_dzialania ... }
: ...
: else { ostateczne_dzialania ... }
W Schemie moglibysmy uzyc kaskady instrukcji "if":
: (if warunek
: (begin dzialania ...)
: (if inny_warunek
: (begin inne_dzialania ...)
: ... (begin ostateczne_dzialania ...) ...))
Taki kaskadowy kod osiaga jednak dosc szybko duzy poziom zaglebienia
i staje sie nieprzyjemny do czytania. Definiujac Lispa, John McCarthy
wprowadzil forme "cond" o nastepujacej skladni:
: (cond (warunek dzialania ...)
: (inny_warunek inne_dzialania ...)
: ...
: (else ostateczne_dzialania ...))
"else" jest w kontekscie formy "cond" symbolem specjalnym. Powyzszy kod
moglby byc przeksztalcony do postaci rekurencyjnej:
: (if warunek
: (begin dzialania ...)
: (cond (inny_warunek inne_dzialania ...)
: ...
: (else ostateczne_dzialania ...)))
zas forme z jednym warunkiem (przypadek brzegowy), np.
: (cond (ostatni_warunek srodki_ostateczne ...))
moglibysmy interpretowac rownowaznie z
: (if ostatni_warunek (begin srodki_ostateczne ...))
** PETLA "while" oraz funkcja "call/cc"
W sekcji objasniajacej dzialanie formy specjalnej "if" podalem przyklad
funkcji obliczajacej silnie. Podany przeze mnie kod byl czysto funkcyjny,
dzieki czemu mozna bylo dokonac analizy jego dzialania za pomoca prostych
podstawien.
Osoby przyzwyzajone do stylu imperatywnego moglyby zapewne chciec zdefiniowac
silnie nastepujaco:
: (define !!
: (lambda (n)
: (let ((result 1))
: (while (> n 0)
: (set! result (* result n))
: (set! n (- n 1)))
: result)))
Uzylismy tutaj petli "while", ktorej zasada dzialania powinna byc znana
wiekszosci programistow. Moglibysmy ja wyrazic przy pomocy wprowadzonych
dotychczas srodkow. Mianowicie chcielibysmy, zeby kod
: (while warunek dzialania ...)
byl transformowany do postaci
: (begin
: (define LOOP
: (lambda ()
: (if warunek
: (begin dzialania ... (LOOP)))))
: (LOOP))
W tym kontekscie warto omowic dzialanie "call/cc". Otoz jest to specjalna
procedura, ktora pobiera jeden argument, bedacy lambda-wyrazeniem od jednego
argumentu. Tym argumentem jest tzw. kontunuacja -- procedura (mogaca przyjmowac
dowolnie wiele argumentow), ktorej wywolanie spowoduje przerwanie wykonywania
biezacej funkcji i przekazanie sterowania do wyrazenia nastepujacego
bezposrednio po wywolaniu call/cc. Owo wyjasnienie moze brzmiec niezrozumiale,
dlatego warto posluzyc sie przykladem:
: (call/cc
: (lambda (return)
: (display "a")
: (return)
: (display "b")))
: (display "c")
Powyzsze wywolanie wypisze ciag znakow "ac" (wypisanie "b" zostanie pominiete).
Procedure call/cc mozemy zastosowac do zaimplementowania instrukcji "break",
znanej z takich jezykow jak C czy Python. Na przyklad, moglibysmy transformowac
powyzsza petle "while" do postaci
: (call/cc
: (lambda (break)
: (define LOOP
: (lambda ()
: (if warunek
: (begin dzialania ... (LOOP)))))
: (LOOP)))
Kontynuacje (czyli pojecie, pod ktore podpadaja takie konstrukcje z jezykow
imperatywnych, jak "exit" w kontekscie programu, "return", "yield" czy "goto"
w kontekscie funkcji, "continue" i "break" w kontekscie petli oraz "throw" i
"catch" w kontekscie wyjatkow) maja w jezyku Scheme status obiektow, ktore
moga byc przekazywane, zachowywane i wielokrotnie wywolywane. Spora ogolnosc
kontynuacji byla przedmiotem krytyki z powodu pewnych trudnosci implementacji,
duzego zuzycia zasobow i niskiej wydajnosci, co sklonilo teoretykow jezykow
programowania do wprowadzenia roznych wariantow kontynuacji o ograniczonym
zasiegu. Osoby zaintersowane szczegolowa dyskusja odsylam do strony
http://okmij.org/ftp/continuations/against-callcc.ht
ml
Tymczasem dodanie do petli "while" instrukcji "continue" pozostawiam jako
cwieczenie dla ciekawskich.
** INNE FORMY SPECJALNE
Podana powyzej lista form specjalnych jest podzbiorem form specjalnych
definiowanych przez standard Scheme'a. Oprocz nich definiuje sie rowniez
m.in. formy "let*", "letrec" czy "do". Moim celem nie jest jednak omowienie
wszystkich form obecnych w jezyku Scheme, ale zarysowanie, w jaki sposob
obecnosc makr zwieksza sile wyrazu jezyka, oraz zademonstrowanie roznych
podejsc do tego, w jaki sposob mozna owe formy specjalne definiowac.
Pod koniec tekstu podam kilka mniej trywialnych zastosowan dla makr,
a tymczasem przejde do omowienia mozliwych (praktycznych) implementacji.
Następne wpisy z tego wątku
- 09.11.14 14:38 g...@g...com
- 09.11.14 16:28 JDX
- 09.11.14 17:39 g...@g...com
- 09.11.14 19:04 JDX
- 09.11.14 19:52 firr
- 09.11.14 20:08 g...@g...com
- 09.11.14 20:28 g...@g...com
- 09.11.14 20:35 firr
- 09.11.14 20:52 A.L.
- 09.11.14 21:51 g...@g...com
- 09.11.14 22:05 g...@g...com
- 09.11.14 22:51 Jordan Szubert
- 09.11.14 22:58 g...@g...com
- 09.11.14 23:36 firr
- 10.11.14 01:06 g...@g...com
Najnowsze wątki z tej grupy
- Arch. Prog. Nieuprzywilejowanych w pełnej wer. na nowej s. WWW energokod.pl
- 7. Raport Totaliztyczny: Sprawa Qt Group wer. 424
- TCL - problem z escape ostatniego \ w nawiasach {}
- Nauka i Praca Programisty C++ w III Rzeczy (pospolitej)
- testy-wyd-sort - Podsumowanie
- Tworzenie Programów Nieuprzywilejowanych Opartych Na Wtyczkach
- Do czego nadaje się QDockWidget z bibl. Qt?
- Bibl. Qt jest sztucznie ograniczona - jest nieprzydatna do celów komercyjnych
- Co sciaga kretynow
- AEiC 2024 - Ada-Europe conference - Deadlines Approaching
- Jakie są dobre zasady programowania programów opartych na wtyczkach?
- sprawdzanie słów kluczowych dot. zła
- Re: W czym sie teraz pisze programy??
- Re: (PDF) Surgical Pathology of Non-neoplastic Gastrointestinal Diseases by Lizhi Zhang
- CfC 28th Ada-Europe Int. Conf. Reliable Software Technologies
Najnowsze wątki
- 2025-01-04 13. Raport Totaliztyczny: Powszechna Deklaracja Praw Człowieka Nie Chroni Przed Wyzyskiem Ani Przed Eksploatacją
- 2025-01-04 Zbieranie danych przez www
- 2025-01-04 reverse engineering i dodawanie elementów do istniejących zamkniętych produktów- legalne?
- 2025-01-04 w Nowym Roku 2025r
- 2025-01-04 Warszawa => Specjalista ds. IT - II Linia Wsparcia <=
- 2025-01-04 Warszawa => Java Developer <=
- 2025-01-04 Warszawa => Spedytor Międzynarodowy <=
- 2025-01-04 Warszawa => System Architect (Java background) <=
- 2025-01-04 Wrocław => Application Security Engineer <=
- 2025-01-04 Chrzanów => Specjalista ds. public relations <=
- 2025-01-04 Katowice => Key Account Manager (ERP) <=
- 2025-01-03 Problem z odczytem karty CF
- 2025-01-03 Jazda z Warszawy do Krakowa teslą
- 2025-01-03 Wrocław => Konsultant Wdrożeniowy Comarch XL/Optima (Księgowość i
- 2025-01-03 Warszawa => International Freight Forwarder <=