-
X-Received: by 10.140.102.239 with SMTP id w102mr911qge.28.1415538737358; Sun, 09 Nov
2014 05:12:17 -0800 (PST)
X-Received: by 10.140.102.239 with SMTP id w102mr911qge.28.1415538737358; Sun, 09 Nov
2014 05:12:17 -0800 (PST)
Path: news-archive.icm.edu.pl!news.icm.edu.pl!newsfeed.pionier.net.pl!feeder.erje.net
!eu.feeder.erje.net!newspeer1.nac.net!border2.nntp.dca1.giganews.com!border1.nn
tp.dca1.giganews.com!nntp.giganews.com!r10no553392igi.0!news-out.google.com!m4n
i0qag.1!nntp.google.com!u7no325427qaz.1!postnews.google.com!glegroupsg2000goo.g
ooglegroups.com!not-for-mail
Newsgroups: pl.comp.programming
Date: Sun, 9 Nov 2014 05:12:17 -0800 (PST)
In-Reply-To: <c...@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>
User-Agent: G2/1.0
MIME-Version: 1.0
Message-ID: <f...@g...com>
Subject: Re: Makra w jezyku Scheme
From: g...@g...com
Injection-Date: Sun, 09 Nov 2014 13:12:17 +0000
Content-Type: text/plain; charset=ISO-8859-1
Lines: 402
Xref: news-archive.icm.edu.pl pl.comp.programming:206865
[ ukryj nagłówki ]* JEZYK SCHEME -- KROTKIE OMOWIENIE
** EWALUACJA WYRAZEN
Do glownych zalet Scheme'a nalezy to, ze laczy on w sobie prostote
i semantyczna sile rachunku lambda z prostota i syntaktyczna sila
lispa. Dzieki tym dwom cechom mozna z latwoscia rozszerzac jezyk
o nowe wyrazenia, w naturalny sposob komponujace sie ze starymi,
a takze zmieniac sposob interpretacji istniejacych wyrazen.
Skladnia jezyka Scheme (podobnie jak wszystkich innych lispow)
jest bardzo prosta i stanowi "w pelni onawiasowana notacje polska".
Programy w lispie sa zlozone z nawiasow (przy czym kazdy nawias
otwierajacy musi miec odpowiadajacy nawias zamykajacy), symboli
(czyli dowolnych ciagow znakow oprocz nawiasow oraz znakow "`",
",", "'", ".", "#", podwojnych cudzyslowiow i bialych znakow.
Dodatkowy warunek jest taki, ze -- aby ciag byl uznany za symbol
-- nie moze byc interpretowany jako liczba) oraz liczb. (Standard
Scheme'a definiuje rowniez inne podstawowe jednostki leksykalne, m.in.
stringi, znaki czy wektory, jednak ze wzgledu na prostote
pominiemy sobie tutaj te kwestie)
Przykladowe wyrazenie arytmetyczne w Schemie mogloby miec zatem
postac:
: (+ (* 3 4) (/ 20 5))
Regula ewaluacji jest prosta: oczekujemy, ze wartoscia pierwszego
elementu listy bedzie funkcja (np. dodawanie, mnozenie itd.),
zas aby poznac wartosc calego wyrazenia, musimy zastosowac
funkcje do wartosci argumentow. Jezeli zatem symbole +, * i /
sa zwiazane z konwencjonalnymi dzialaniami arytmetycznymi,
powyzsze wyrazenie mozemy zgodnie z ta regula najpierw przeksztalcic do
: (+ 12 4)
a nastepnie do
: 16
** FORMY SPECJALNE
*** FORMA "quote"
Ciekawa wlasnoscia lispa jest tzw. homoikonicznosc: kod zrodlowy
programow stanowi liste symboli, liczb i ewentualnie innych list,
zas listy, symbole i liczby sa typami danych, na ktorych programy
lispowe moga operowac. Aby powstrzymac ewaluator przed interpretowaniem
symbolu, trzeba uzyc operatora "quote". Wartoscia wyrazenia
: (quote x)
bedzie
: x
Operator "quote" dziala inaczej, niz uzyte powyzej operatory arytmetyczne.
Operatory arytmetyczne (domyslnie) stanowia zwykle funkcje, zas "quote"
jest forma specjalna, ktora charakteryzuje sie tym, ze nie ewaluuje swoich
argumentow. Lisp traktuje zapis 'x rownowaznie z zapisem (quote x).
Aby uzyskac liste symboli (a b c), moglibysmy uzyc funkcji "list":
: (list 'a 'b 'c)
: ===>
: (a b c)
Operator "quote" dziala jednak nie tylko na symbole, ale rowniez na cale
wyrazenia, wiec powyzszy wynik moglibysmy uzyskac rowniez piszac po prostu
: '(a b c)
: ===>
: (a b c)
*** FORMA "lambda"
Oprocz operatora "quote", w jezyku Scheme wystepuje 5 innych podstawowych
form specjalnych. Jedna z nich jest forma "lambda", ktora ma nastepujaca
postac:
: (lambda (argumenty ...) cialo + ...)
Forma "lambda" jest bardzo potezna i w zasadzie wzieta sama w sobie
stanowi kompletny jezyk programowania, pozwalajacy na wyrazenie instrukcji
warunkowych "if-then-else" oraz liczb naturalnych. Osobom zainteresowanym
tym zagadnieniem polecam kurs programowania funkcyjnego autorstwa Johna
Harrisona:
http://www.cl.cam.ac.uk/teaching/Lectures/funprog-jr
h-1996/index.html
Mowiac najkrocej, wyrazenie lambda tworzy nowa funkcje. Najprostszy
przyklad moglby wygladac nastepujaco:
: (lambda (x y)(+ x (* x y)))
W wyniku dostajemy funkcje dwuargumentowa, ktora dodaje swoj pierwszy
argument do iloczynu obu argumentow. Gdybysmy chcieli uzyc tej funkcji,
moglibysmy napisac:
: ((lambda (x y)(+ x (* x y))) 3 4)
Aplikacje wyrazenia lambda mozna pojmowac w taki sposob, ze zastepujemy
cale wyrazenie lambda jego cialem, w ktorym symbole uzyte jako argumenty
zastepujemy wartosciami tych argumentow. W powyzszym przypadku byloby to:
: (+ 3 (* 3 4))
Choc moze to wygladac niepozornie, majac do dyspozycji te regule, mozemy
wyrazic dowolna funkcje rekurencyjna (za sprawa tzw. kombinatorow punktu
stalego, w szczegolnosci -- kombinatora Y).
Dodatkowo Scheme pozwala nam zdefiniowac funkcje mogaca przyjmowac dowolnie
wiele argumentow, jezeli zamiast listy argumentow podamy pojedynczy symbol.
Wowczas z owym symbolem zostaje w ciele funkcji zwiazana lista wszystkich
przekazanych argumentow:
: ((lambda args args) 1 2 3)
: ===>
: (1 2 3)
*** FORMA "define"
Kolejna forma specjalna jest forma "define", ktora pozwala nam nazywac
rozne obiekty. Na przyklad moglibysmy zdefiniowac podnoszenie do kwadratu:
: (define square (lambda (x) (* x x)))
Operacja ta wiaze funkcje, ktora mnozy swoj jedyny argument przez siebie,
z symbolem "square". Zapis
: (square 5)
jest rownowazny zapisowi
: ((lambda (x) (* x x)) 5)
co na mocy wczesniejszej reguly mozna przeksztalcic do
: (* 5 5)
Formy "define" mozna rowniez uzyc do wprowadzenia definicji w zasiegu
wyrazenia "lambda", np.
: (define x 5) ; zasieg zewnetrzny
: x
: ===> 5
: ((lambda () (define x 20) x))
: ====> 20
: x
: ===> 5 ; wartosc w zasiegu zewnetrznym nie ulegla zmianie
Warto wiedziec, ze formalnie nie uznaje sie definicji za wyrazenia,
i na przyklad zapis
: (lambda () (define x 20))
jest bledny, poniewaz cialo wyrazenia lambda musi zawierac przynajmniej
jedno wyrazenie.
*** FORMA "if"
Kolejna forma specjalna, ktora zasluguje na uwage, jest forma
warunkowa "if", o nastepujacej skladni:
: (if warunek wyrazenie-gdy-warunek-spelniony)
lub
: (if warunek
: wyrazenie-gdy-warunek-spelniony
: wyrazenie-w-przeciwnym-razie)
Forma "if" dziala w taki sposob, ze najpierw dokonuje ewaluacji warunku,
i jezeli wartosc warunku jest rozna od wartosci falszu (zapisywanej w Schemie
jako "#f" albo -- wg. najnowszego standardu -- jako "#false"), to
wartoscia calego wyrazenia staje sie wartosc *wyrazenia-gdy-warunek-spelniony*,
zas w przeciwnym razie wartosc wyrazenia albo jest nieokreslona (dla wariantu
pierwszego), albo jest wartoscia *wyrazenia-w-przeciwnym-razie*.
Forma "if" pozwala na definiowanie zlozonych funkcji. Klasycznym przykladem
jest funkcja "silnia":
: (define ! (lambda (n) (if (= n 0) 1 (* n (! (- n 1))))))
Zgodnie z regulami ewaluacji, wyrazenie
: (! 5)
mozna zinterpretowac nastepujaco:
: ((lambda (n) (if (= n 0) 1 (* n (! (- n 1))))) 5)
: ===>
: (if (= 5 0) 1 (* 5 (! (- 5 1))))
: ===>
: (* 5 (! 4))
: ===>
: (* 5 ((lambda (n) (if (= n 0) 1 (* n (! (- n 1))))) 4))
: ===>
: (* 5 (if (= 4 0) 1 (* 4 (! (- 4 1)))))
: ===>
: (* 5 (* 4 (! 3)))
: ===>
: (* 5 (* 4 ((lambda (n) (if (= n 0) 1 (* n (! (- n 1))))) 3)))
: ===>
: (* 5 (* 4 (if (= 3 0) 1 (* 3 (! (- 3 1))))))
: ===>
: (* 5 (* 4 (* 3 (! 2))))
: ===>
: (* 5 (* 4 (* 3 ((lambda (n) (if (= n 0) 1 (* n (! (- n 1))))) 2))))
: ===>
: (* 5 (* 4 (* 3 (if (= 2 0) 1 (* 2 (! (- 2 1)))))))
: ===>
: (* 5 (* 4 (* 3 (* 2 (! 1)))))
: ===>
: (* 5 (* 4 (* 3 (* 2 ((lambda (n) (if (= n 0) 1 (* n (! (- n 1))))) 1)))))
: ===>
: (* 5 (* 4 (* 3 (* 2 (if (= 1 0) 1 (* 1 (! (- 1 1))))))))
: ===>
: (* 5 (* 4 (* 3 (* 2 (* 1 (! 0))))))
: ===>
: (* 5 (* 4 (* 3 (* 2 (* 1 ((lambda (n) (if (= n 0) 1 (* n (! (- n 1))))) 0))))))
: ===>
: (* 5 (* 4 (* 3 (* 2 (* 1 (if (= 0 0) 1 (* 0 (! (- 0 1)))))))))
: ===>
: (* 5 (* 4 (* 3 (* 2 (* 1 1)))))
: ===> ... ===>
: 120
*** FORMA "set!"
Forma "set!" powoduje przypisanie nowej wartosci do istniejacej (tzn. zwiazanej)
zmiennej. Zmienna moze byc zwiazana albo przy pomocy formy "define", albo
jako parametr formalny w formie "lambda"
: (define x 5)
: x
: ===> 5
: ((lambda (x) (set! x (+ x 1)) x) 7) ; zmiana wartosci zmiennej lokalnej
: ===> 8
: x
: ===> 5
: ((lambda () (set! x (+ x 1)))) ; zmiana wartosci zmiennej zewnetrznej
: x
: ===> 6
*** FORMA "begin"
Formy "begin" uzywamy do grupowania wyrazen, np. wewnatrz ktorejs galezi
formy "if". Warto jednak zwrocic uwage, ze zapis
: (begin definicje/wyrazenia ...)
nie jest rownowazny zapisowi
: ((lambda () definicje/wyrazenia ...))
poniewaz forma "begin" nie wprowadza nowego zasiegu. W szczegolnosci
forma "begin" moze zawierac wylacznie definicje, i np. zapis
: (begin (define symbol-1 wartosc-1) (define symbol-2 wartosc-2))
jest rownowazny zapisowi:
: (define symbol-1 wartosc-1)
: (define symbol-2 wartosc-2)
** FUNKCJE WBUDOWANE
Lista funkcji wbudowanych nie jest szczegolnie istotna. W dotychczasowych
przykladach uzywalem funkcji +,*,-,/,= oraz list.
*** FUNKCJA "apply"
Jest jednak kilka funkcji, ktore zasluguja na szczegolna uwage. Pierwsza
z nich jest "apply". Zapis
: (funkcja argumenty ...)
jest rownowazny zapisowi
: (apply funkcja (list argumenty ...)).
Na przyklad zamiast
: (+ 1 2)
mozna napisac
: (apply + '(1 2))
Ponadto funkcja "apply" moze byc uzyta z dodatkowymi argumentami pomiedzy
argumentem funkcyjnym a lista. Wowczas elementy pomiedzy pierwszym a ostatnim
argumentem zostana dopisane na poczatku ostatniego argumentu. W zwiazku z tym
nastepujace wywolania sa rownowazne:
: (+ 1 2 3)
: (apply + '(1 2 3))
: (apply + 1 '(2 3))
: (apply + 1 2 '(3))
: (apply + 1 2 3 '())
*** FUNKCJE "values" i "call-with-values"
Pewna specyficzna cecha Scheme'a jest to, ze zdefiniowane w nim funkcje moga
zwracac wiecej niz jedna wartosc. Do zwracania wielu wartosci sluzy funkcja
"values", ktora pobiera dowolnie wiele argumentow:
: (values 1 2 3)
: ===> 1
: ===> 2
: ===> 3
Do przechwycenia tych wartosci sluzy funkcja call-with-values, ktora pobiera
dwie funkcje -- producenta (0-argumentowego) i konsumenta (n-argumentowego), np.
: (call-with-values (lambda()(values 1 2 3)) (lambda(a b c)(+ a b c)))
*** FUNKCJE "cons", "car" i "cdr"
Do tej pory w kilku przykladach uzylem dowolnie-wielo-argumentowej funkcji
"list", ktorej wartoscia jest lista podanych do niej argumentow. Warto
jednak wiedziec nieco wiecej o architektonice list. Po pierwsze, istnieje
w Schemie specjanly symbol na oznaczenie listy pustej, a jest on zapisywany tak:
: '()
Po drugie, listy skonstruowane sa z par. Do tworzenia par sluzy funkcja cons:
: (cons 'a 'b)
: ===> (a . b)
Po trzecie, funkcje car i cdr sluza do pobrania odpowiednio pierwszego
i drugiego elementu pary:
: (car (cons 'a 'b))
: ===> a
: (cdr (cons 'a 'b))
: ===> b
Elementy (car x) i (cdr x) bedziemy od tej pory nazywac odpowiednio glowa
i ogonem listy.
Po czwarte, zapis
: (a . (b . (c . ())))
jest rownowazny zapisowi
: (a b c)
zas zapis
: (a . (b . (c . d)))
zapisowi
: (a b c . d)
dla dowolnych dopuszczalnych wartosci a, b, c, d). Jezeli drugi element
ostatniej pary listy nie jest lista pusta, to taka liste nazywamy
"lista kropkowana" ("dotted list").
Stad tez (list 1 2 3) jest rownowazne (cons 1 (cons 2 (cons 3 '()))).
*** PREDYKATY POROWNUJACE: "=", "<", "<=", ">", ">=", "eq?"
Oprocz uzytej w jednym z poprzednich przykladow funkcji "=", sprawdzajacej
rownosc numeryczna, Scheme definiuje kilka innych uzytecznych predykatow
do operowania na liczbach, m.in. "<" (mniejszy od), ktory zwraca
prawde wtw jej argumenty (liczbowe) stanowia ciag rosnacy, np.
: (< 1 3 7)
: ===> #t ; gdzie #t to specjalna wartosc odpowiadajaca prawdzie logicznej
: (< 3 7 1)
: ===> #f
Pozostale funkcje porownujace ("<=", ">", ">=") dzialaja tak, jak mozna
sie po nich spodziewac. Na uwage zasluguje predykat eq?, ktory sprawdza,
czy dwa obiekty sa tym samym obiektem -- na przyklad, czy dwa symbole
sa tym samym symbolem. W przypadku list dzialanie tej funkcji moze byc
zaskakujace:
: (define a '(1 2 3))
: (define b '(1 2 3))
: (eq? a b)
: ===> #f
Wynika to stad, ze listy a i b stanowia osobne obiekty w pamieci.
(W pewnych przypadkach niektore kompilatory moglyby zoptymalizowac powyzszy
kod w taki sposob, ze a i b bylyby tym samym obiektem, i wowczas uzycie
funkcji eq? moze zwrocic #t).
Lista pusta jest zawsze tozsama ze soba, tj.
: (eq? '() '())
: ===> #t
*** UWAGI O FUNKCJI "call-with-current-continuation" ("call/cc")
Ostatnia osobliwa funkcja jest call-with-current-continuation, zazwyczaj
skracana jako call/cc. Z pewnych wzgledow omowie ja dopiero pozniej, gdy
bede mial mozliwosc zademonstrowania jej dzialania na konkretnym przykladzie.
Następne wpisy z tego wątku
- 09.11.14 14:34 g...@g...com
- 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
Najnowsze wątki z tej grupy
- Popr. 14. Nauka i Praca Programisty C++ w III Rzeczy (pospolitej)
- 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
Najnowsze wątki
- 2025-01-19 Test - nie czytać
- 2025-01-19 qqqq
- 2025-01-19 Tauron przysyła aneks
- 2025-01-19 Nowa ładowarka Moya a Twizy -)
- 2025-01-18 Power BANK z ładowaniem przelotowym robi PRZERWY
- 2025-01-18 Pomoc dla Filipa ;)
- 2025-01-18 znowu kradno i sie nie dzielo
- 2025-01-18 Zieloni oszuchiści
- 2025-01-18 Zielonka => Specjalista ds. public relations <=
- 2025-01-18 Warszawa => Frontend Developer (JS, React) <=
- 2025-01-18 Warszawa => Software .Net Developer <=
- 2025-01-18 Warszawa => Developer .NET (mid) <=
- 2025-01-18 Katowice => Administrator IT - Systemy Operacyjne i Wirtualizacja <=
- 2025-01-17 Zniknął list gończy za "Frogiem". Frog się nam odnalazł?
- 2025-01-17 Kto wytłumaczy "głupiemu" prezydentowi Dudzie wielką moc prawną "dekretu premiera" TUSKA? [(C)Korneluk (2025)]