英国私人补习班报名火爆 学者:恐影响教育公平
![]() | |
Paradigma | funkcionální programování |
---|---|
Vznik | 1975 |
Autor | Guy L. Steele a Gerald Jay Sussman |
Typová kontrola | silné, dynamické |
Hlavní implementace | PLT Scheme, MIT/GNU Scheme, Scheme 48, Chicken, Gambit, FLUENT, Guile, Bigloo, Chez Scheme, STk, STklos, Larceny, SCM |
Dialekty | T |
Ovlivněn jazyky | Lisp, ALGOL |
Ovlivnil jazyky | Common Lisp, JavaScript, Ruby |
Scheme je multiparadigmaticky programovací jazyk. Funkcionální programovací paradigma pat?í mezi tzv. funkcionální paradigmata. Scheme je jeden ze dvou hlavních dialekt? funkcionálního programovacího jazyka Lisp. Jazyk navrhli Guy Lewis Steele a Gerald Jay Sussman a jeho první popis byl sepsán v roce 1975. Scheme byl p?edstaven akademickému světu skrze sérii ?lánk?, nyní známych jako Sussmanovy a Steelovy Lambda Papers.[1] Jazyk Scheme definují dva standardy: oficiální IEEE standard a standard nazyvany Revisedn Report on the Algorithmic Language Scheme, ve zkratce RnRS, kde n je ?íslo revize. Sou?asny standard je R5RS[2], a R6RS[3] je ve vyvoji.
Oproti Lispu se Scheme sna?í o minimalismus – poskytovat co nejmen?í po?et základních funkcí, na nich? jsou pak v knihovnách postaveny slo?itěj?í konstrukce. Díky tomu má dosud poslední reference jazyka jen 50 stran.
Scheme byl prvním dialektem Lispu, ktery nabízel volbu mezi lexikálním nebo dynamickym rozsahem platnosti proměnné. Také byl jedním z programovacích jazyk?, ktery podporoval ?first-class continuation“.
Tento jazyk je v praxi pou?ívany jen z?ídka, pou?ívá se p?edev?ím ve ?kolách pro vyuku programování algoritm?. Nejznáměj?í implementací je graficky editor GIMP, jeho? dodate?né zásuvné moduly a skripty jsou psány v dialektu jazyka Scheme.
P?vod
[editovat | editovat zdroj]Na po?átku zrodu jazyka Scheme stála pot?eba Guye Steela a Geralda Sussmana z MIT (Massachusettsky technicky institut), vyzkou?et si některé aspekty modelu aktor?, ktery v roce 1973 ve?ejnosti p?edstavil Carl Hewitt. Proto?e LISP se k tomuto p?íli? nehodil, bylo pot?eba navrhnout novy jazyk. Ten byl nakonec implementován v LISPu. A dokonce i syntaxí LISP hodně p?ipomínal. Byl v?ak o dost jednodu??í, a odstraňoval některé z nep?íjemnych vlastností LISPu.
"Chceme lépe porozumět Hewittovu Aktor modelu, ale máme problémy vztáhnout aktor model a jeho neobvyklou terminologii známych programovych notací. Plánovali jsme zkonstruovat ukázkovou implementaci aktor jazyka tak, abychom si s ní mohli hrát. Pou?itím MacLisp, jako?to pracovního prost?edí, jsme napsali tenky interpret Lispu a poté p?idali mechanismus k vytvá?ení aktor? a posílání zpráv.?
Poprvé byl jazyk Scheme ve?ejně popsán v roce 1975 v práci Sussmana a Steela “ Scheme: an interpreter for extended lambda calculus". V roce 1976 pak Sussman a Steele napsali dvě publikace "LAMBDA: The Ultimate Imperative" a "LAMBDA: The Ultimate Declarative", v nich? popsali, jak ?e?it bě?né programové konstrukce.
V roce 1978 byl jazyk Scheme standardizován. Základem se stala "Revidovaná zpráva o Scheme" – dialektu LISPu. Tato zpráva popisovala vyvoj jazyka, poté co byla MIT implementace roz?í?ena o podporu inovativního kompilátoru. Dal?í zpráva, která byla nazvána "Revize revize reportu Scheme, neboli neobvykly LISP" byla publikována v roce 1985. Tradice revizí revize revize se zachovala a dnes je ji? na světě poslední pátá revize z února roku 1998.
P?vodní název jazyka byl Schemer. Po vzoru dobovych jazyk? pro umělou inteligenci Planner a Conniver. Proto?e v?ak auto?i pou?ívali opera?ní systém ITS, ktery limitoval délku soubor? a adresá?? ?esti znaky, byly v?dy soubory pro Schemer ulo?eny v adresá?i Scheme. Z toho vze?el název Scheme, ktery tak nahradil Schemer.
Budoucnost
[editovat | editovat zdroj]Novy standardiza?ní proces za?al na 2003 Scheme workshopu, s cílem vytvo?ení R6RS standardu v roce 2006. R6RS p?inese standardní modulární systém; povolí dělit mezi jádrem jazyka a knihovnami. Koncept R6RS specifikace (?ertovně pojmenovany "R5.91RS") byl uvolněn k testování v ?íjnu 2006. Aktualizovany koncept, R5.92RS, byl uvolněn 19. ledna 2007, a dal?í, R5.93RS, 22. b?ezna 2007. Poslední koncept je R5.95RS a byl uvolněn 25. ?ervna 2007.
Ukázka kódu
[editovat | editovat zdroj]Tradi?ní program hello world vypadá v jazyce Scheme t?eba takto:
(define (hello)
(display "Ahoj svete!")
(newline))
(hello)
Na prvním ?ádku za?íná definice procedury hello, která vypí?e text ?Ahoj svete!“ a od?ádkuje. Na ?tvrtém ?ádku je pak tato procedura zavolána.
P?íkaz define slou?í také k definici proměnnych:
(define pi 3.14)
Následující p?íklad ukazuje definici funkce, která vypo?ítá faktoriál zadaného ?ísla:
(define fact
(lambda (n)
(if (= n 0)
1
(* n (fact (- n 1))))))
Psaní konstrukce lambda m??e byt zdlouhavé, a tak Scheme nabízí zkratku:
(define (fact n)
(if (= n 0)
1
(* n (fact (- n 1)))))
Funkci pak lze zavolat:
(fact 4)
Na vystupu bychom dostali ?íslo 24. Vy?e uvedeny p?íklad ukazuje několik zajímavych konstrukcí. Jednak je z?ejmé, ?e v jazyce Scheme se pou?ívá prefixového zápisu:
(+ 1 2) ; sou?et
(- 5 3) ; rozdíl
(* 4 5) ; sou?in
(/ 9 3) ; podíl
(+ 1 3 7) ; není t?eba se omezovat na dvě ?ísla
Druhou zajímavou věcí je podmínka if. Ta má tvar (if (vyraz) true false), kde větev true se provede, je-li vyraz pravdivy (není-li vyhodnocen jako #f), větev false v p?ípadě, ?e je vyraz nepravdivy (#f; ekvivalentní ?ásti else v jinych jazycích).
T?etí zajímavou věcí je rekurzivní volání sebe sama na pátém ?ádku definice funkce. Funkci pro vypo?et faktoriálu lze p?epsat:
(define (fact n)
(let fact-iter ((n n)
(result 1))
(if (= n 0)
result
(fact-iter (- n 1) (* n result)))))
V takovém to p?ípadě budou v?echna rekurzivní volání koncově rekurzivní. Pr?bě?né hodnoty nejsou ukládány na zásobník, ale jsou p?edávány jako argumenty rekurzivní funkce a interpret, m??e zahodit obsah zásobníku a znovu zavolat funkci. Tzn. ?e vypo?et funkce probíhá v konstantním pamě?ovém prostoru. Standard jazyka Scheme R5RS, p?esně definuje, kdy dojde ke koncovému volání. V ukázce kódu je také pou?itá konstrukce ?pojmenovany let“, která se pou?ívá na vytvo?ení rekurze v těle funkce, ani? bychom explicitně definovali funkci v globálním prost?edí. To lze také za pomoci lambda vyraz?:
(define fact
((lambda (f) (f f))
(lambda (self)
(lambda (n)
(if (= n 0)
1
(* n ((self self) (- n 1))))))))
Elementy jazyka
[editovat | editovat zdroj]Komentá?e
[editovat | editovat zdroj]Ka?dy komentá? je uvozen st?edníkem (;) a je platny po cely zbytek ?ádku. Některé implementace dovolují zakomentovat více ?ádk?, obalí-li se do #|…|#.
Identifikátory
[editovat | editovat zdroj]- extrémně volná pravidla;
- mohou obsahovat:
- písmena a–z, A–Z ;
- ?íslice;
- znaky ? ! . + – / < = > : $ % ^ & _ ~
- nesmí obsahovat závorky;
p?íklady:
x3, prumerny-plat, Maximum, ?$*
Konvence pro identifikátory
[editovat | editovat zdroj]- jména predikát? (vracejí pravdivostní hodnotu) kon?í otazníkem, nap?. number?;
- jména procedur s vedlej?ími efekty (nap?. změna hodnoty nějaké proměnné) kon?í vyk?i?níkem, nap?. pridej-prvek!;
- procedury konvertující jeden typ na druhy byvají pojmenovány
typ1->typ2
.
?ísla
[editovat | editovat zdroj]- celá: 160, +24, –78;
- racionální (zlomky): 1/2, –29/30;
- s plovoucí ?ádovou ?árkou: 3.14, .33, –7.689e4;
- komplexní: 3+2i;
- nemá p?ísnou typovou kontrolu ani typované proměnné, vypo?et m??e kombinovat několik typ?.
?etězce
[editovat | editovat zdroj]?etězce jsou uzav?eny do dvojitych uvozovek: "ahoj světe".
Pravdivostní hodnoty
[editovat | editovat zdroj]- true a false zapisovány jako #t a #f
- revidovaná specifikace umo?ňuje místo #f pou?ívat ve stejném vyznamu i prázdny seznam ()
Dvojice
[editovat | editovat zdroj]Základem jazyka Scheme jsou te?kové páry. Je to (jediná) slo?ená datová struktura s konstruktorem cons a selektory car a cdr [kudr]. Te?kovy pár m??e nap?íklad reprezentovat 2D sou?adnice, imaginární ?íslo, nebo ?eské a cizí slovo ve slovníku.
> (define a (cons 1 2))
> a
(1 . 2)
> (car a)
1
> (cdr a )
2
Seznamy
[editovat | editovat zdroj]Seznamy jsou definovány rekurzivně pomocí dvojic. Ka?dy seznam je definován jako posloupnost te?kovych pár?, p?i?em? poslední te?kovy pár má na své druhé pozici prázdny seznam.
> (cons 1 (cons 2 (cons 3 ())))
(1 2 3)
Mohou obsahovat atomické hodnoty i dal?í seznamy. Lze je vno?ovat : ((1) (2 (3 4) 5 6) 7 ((8)))
. V?echny seznamy mají kone?nou délku a jsou ukon?eny prázdnym seznamem.
- prázdny seznam je reprezentován konstantami nil, ()
- seznam s jedním prvkem:
(cons 1 () )
- seznam s jedním prvkem:
- neprázdny seznam je dvojice hlava (první prvek) a ocas (seznam zbylych prvk?), anglicky head a tail
- uzav?en do závorek, prvky oddělovány mezerami:
(a b c), (12 "?roubek" .8)
- uzav?en do závorek, prvky oddělovány mezerami:
- procedura list: konstrukce seznamu, s proměnnym po?tem argument?.
> (list 1 2 3)
(1 2 3)
K p?istupování k hodnotám v seznamu slou?í funkce car a cdr.
- car – vrací první prvek v seznamu (hlavi?ku), seznam musí byt nenulovy;
- cdr – vrací zbytek seznamu (ocásek), pokud seznam obsahuje jediny prvek, vrací prázdny seznam;
- p?íklad: zisk t?etího prvku seznamu:
(car (cdr (cdr x)))
.
Procedury pro seznamy
[editovat | editovat zdroj](list? x)
je x seznam?(pair? x)
je x pár?(null? x)
je x prázdny seznam?(list operandy)
vyhodnotí operandy a vytvo?í seznam obsahující vysledky vyhodnocení(list 6 (* 3 5) 'a)
vytvo?í seznam (6 15 a)
(length seznam)
po?et prvk? seznamu(append seznam1 seznam2 seznam3 …)
spojí seznamy do jednoho(reverse seznam)
obrátí po?adí prvk? v seznamu
Dal?í ukázky práce se seznamy
[editovat | editovat zdroj];odstraneni prvniho vyskytu prvku ze seznamu
(define (odstran-prvni p s)
(cond ((null? s) '())
((equal? p (car s)) (cdr s))
(else (cons (car s) (odstran-prvni p (cdr s))))))
;odstrani vsechny vyskyty prvku ze seznamu
(define (odstran-vsechny p s)
(cond ((null? s) '())
((equal? p (car s)) (odstran-vsechny p (cdr s)))
(else (cons (car s) (odstran-vsechny p (cdr s))))))
;; vrátí n-ty prvek ze seznamu
;; nehlídáme p?itom, zda je index mimo seznam
(define (nprvek index seznam)
(if (= index 0) (car seznam)
(nprvek (- index 1) (cdr seznam))))
(nprvek 4 '(jan ales marketa petr josef))
;; N-ty prvek pole v?etně kontroly, zda nejsme mimo index
;; Reagovat m??eme jakkoliv -- vrátit specifickou chybu nebo t?eba prázdny seznam.
(define (nprvek index seznam)
(if (>= index (length seznam))
(error "Index je mimo seznam")
(let nprvek ((index index)
(seznam seznam))
(if (= index 0)
(car seznam)
(nprvek (- index 1) (cdr seznam))))))
;spojeni seznamu - vzdy prvni prvek s prvnim
(define (spoj-prvni s1 s2)
(if (or (null? s1) (null? s2)) '()
(cons (cons (car s1) (car s2))
(spoj-prvni (cdr s1) (cdr s2)))))
(odstran-prvni 'ivan '(jan ales libor tomas radek petr ivan ivan))
(odstran-vsechny 'ivan '(jan ales libor tomas radek petr ivan ivan ivan ivan))
(spoj-prvni '(milos ales petr jan alan) '(janicek novak kral novotny klaus havel))
;; Mo?ná implementace funkce map beroucí pouze jeden seznam
(define (my-easy-map funkce seznam)
(if (null? seznam)
'()
(cons (funkce (car seznam))
(my-easy-map funkce (cdr seznam)))))
(my-easy-map - '(1 2 3 4 5 6))
; Vrátí: (-1 -2 -3 -4 -5 -6)
Proměnné
[editovat | editovat zdroj]- dynamicky typované
- uvozeny vyrazem define.
(define var1 value)
Vyraz define
modifikuje vazbu symbolu v aktuálním prost?edí. Oproti tomu speciální forma let
vytvá?í nové prost?edí (scope) a v tomto prost?edí navazuje na symboly nové vazby. let
jako takovy nedoká?e p?epsat ji? existující vazbu, v?dy pouze vytvá?í nová prost?edí. To je hlavní rozdíl oproti speciální formě define
, ktery doká?e p?epsat existující vazby.
(let ((var1 value))
...
; scope of var1
...)
Rozdíl mezi let
a define
m??eme z?ásti ilustrovat na následujícím p?íkladu:
(let ((a 10))
(cons
(let ((a 20))
(define a 30)
a)
a))
První let
vytvo?í své prost?edí, ve kterém navá?e na a
hodnotu 10. Druhy let také vytvo?í prost?edí a navá?e na a
hodnotu 20. Pokud bychom nepou?ili define
, byl by vysledkem operace te?kovy pár 20 . 10
, proto?e sice existují dva symboly a
, ale v jinych prost?edí, kde mají vlastní vazbu. define
ale modifikuje vazbu v aktuálním prost?edí, tak?e ve vno?eném vnit?ním letu změní vazbu symbolu a
na t?icet. Vysledkem operace tak bude te?kovy pár 30 . 10
.
let
je pouze konven?ní syntaxe, která není nezbytná a m??e byt p?ímo nahrazena pou?itím procedury. Nap?íklad kód vy?e je p?ímym ekvivalentem zápisu:
((lambda (var1)
...
; scope of var1
...) value)
Procedury
[editovat | editovat zdroj]1 (define fun
(lambda (arg1 arg2)
...))
2 (define (fun arg1 arg2)
...)
3 (fun value1 value2)
Procedury jsou ve Scheme first-class objekty. Mohou byt argumenty jinych procedur a mohou byt jinymi procedurami vraceny. Mohou byt p?i?azeny do proměnné. Procedury jsou tvo?eny lambda
formami. Nap?íklad procedury se dvěma argumenty arg1
jsou definovány na ?ádku 1, ?ádek 2 je krat?í, ekvivalentní vyraz. ?ádek 3 ukazuje jak jsou procedury spou?těny. Na prvním místě je název procedury a zbytkem jsou její argumenty.
V Scheme jsou procedury rozděleny do dvou základních kategorií: u?ivatelské procedury a primitiva (primitivní procedury). V?echna primitiva jsou procedury, ale ne v?echny procedury jsou primitiva. Primitiva jsou p?eddefinované funkce jazyka Scheme. To zahrnuje nap?. +
, -
, *
, /
, set!
, car
, cdr
, a dal?í. V r?znych variacích Scheme m??e u?ivatel redefinovat primitivum. P?íklad:
(define (+ x y)
(- x y))
nebo jednodu?e
(define + -)
co? zp?sobí, ?e +
primitivum provede rozdíl namísto sou?tu.
Cykly
[editovat | editovat zdroj]Cykly ve standardu Scheme neexistují, ale v r?znych implementacích se m??eme setkat nap?íklad s cyklem do
. A?koliv programujeme-li funkcionálně, cykly nevyu?ijeme, proto?e jsou zalo?ené na vedlej?ím efektu. ?astěji se pou?ívá rekurze. Syntaxe cyklu do
je následující:
(do ((<proměnná1> <vychozí hodnota 1> <změna1>)
(<proměnná2> <vychozí hodnota 2> <změna2>)
... )
(<test1> <test2>)
<p?íkaz1>
<p?íkaz2>
... )
Nejd?íve následuje seznam proměnnych, které budou iterovat, v?etně vychozí hodnoty a indikátoru změny po ka?dé iteraci. Jako druhy argument je uvedena ukon?ující podmínka cyklu. Ve chvíli, kdy je splněna, je cyklus ukon?en. Následuje seznam p?íkaz?, které se mají v cyklu provést. P?íklad jednoduchého cyklu, ktery vytiskne ?ísla od jedné do devíti:
(do ((x 1 (+ x 1)))
((= x 10))
(print x)
(newline))
P?íklad cyklu procházející seznam:
(do ((x '(1 2 3 4 5 6) (cdr x)))
((null? x))
(print (car x))
(newline))
Rovnost
[editovat | editovat zdroj]Scheme rozli?uje t?i druhy rovnosti: "eq?
" vrací #t
jestli?e jeho parametry reprezentují stejné datové objekty v paměti; "eqv?
" je to samé jako eq?
, ale zachází s některymi objekty (nap?. znaky a ?ísly) speciálně tak, ?e ?ísla, která jsou si =
jsou také eqv?
pouze kdy? nejsou eq?
; equal?
porovnává datové struktury jako seznamy, vektory, ?etězce k zji?tění, ?e mají stejnou strukturu a eqv?
obsah.
V Scheme dále existují: string=?
; porovnání ?etězc?; char=?
porovnání znak?; =
porovnání ?ísel
?ídící struktury
[editovat | editovat zdroj]Vyhodnocování podmínek
[editovat | editovat zdroj]Pro vyhodnocování podmínek nabízí Scheme t?i speciální formy. If, case a cond. If se a? na formu zápisu nijak neli?í od if, které pou?ívá vět?ina ostatních jazyk?. Forma cond dovoluje pou?ít libovolné mno?ství podmínek a návratovou hodnotu pro ka?dou z nich. Forma case je podobná formě cond postupně vyhodnocuje seznamy a pokud nalezne odpovídající prvek, vrátí jeho p?íslu?nou hodnotu.
Pou?ití if
:
(if test then-expr else-expr)
Vyraz test
je vyhodnocen takto: jestli?e vysledek vyhodnocení je ?true“ (co? je něco jiného ne?li #f
), pak je vyhodnocen vyraz then-expr
, jinak else-expr
.
Pou?ití cond
:
(cond (test1 expr1 ...)
(test2 expr2 ...)
...
(else exprn))
První vyraz, ktery bude true, bude vyhodnocen, jestli?e v?echny vysledky jsou #f
, pak je vyhodnocena else
klauzule.
Vstup/Vystup
[editovat | editovat zdroj]Scheme u?ívá konceptu port? pro ?tení a zápis. R5RS definuje dva vychozí porty, p?ístupné pomocí funkcí current-input-port
a current-output-port
, co? koresponduje s Unixovymi pojmy stdin and stdout. Mnoho implementací poskytuje té? current-error-port
.
Makra
[editovat | editovat zdroj]Scheme zná makra, co? je velice mocná zbraň v rukou programátora. Makra transformují zdrojovy kód, makroexpanzi provádí preprocesor a samotny interpret u? ?ádná makra nevidí, vidí pouze hotovy zdrojovy kód, ktery je ur?en ke zpracování. Pomocí maker si programátor m??e dovolit r?zné věci, které by jinak nebyl schopny provést. První p?íklad bude anaforicky if, ktery se chová podobně jako klasicky if, pouze si vysledek podmínky uchovává do symbolu it
, tak?e v těle anaforického ifu se m??eme lehce odkázat na vysledek podmínky:
(define-macro aif
(lambda (cond true false)
`(let ((it ,cond))
(if it
,true
,false))))
;; P?íklady pou?ití
(aif (+ 5 5) it #f)
; 10
(aif (member 3 '(1 2 3 4 5 6)) it #f)
; (3 4 5 6)
Dal?í p?íklad je makro dolist
, které provádí iteraci p?ímo nad seznamem. Bere jako argument itera?ní symbol, do kterého se bude v?dy ukládat hodnota aktuálně procházeného prvku seznamu, seznam samotny a pak tělo.
(define-macro (dolist instrukce . telo)
(let ((symbol (car instrukce))
(seznam (cadr instrukce))
(iter (gensym)))
`(do ((,iter ',seznam (cdr ,iter))
(,symbol (car ',seznam)))
((null? ,iter))
(set! ,symbol (car ,iter))
,@telo)))
;; P?íklady pou?ití
(dolist (x (1 2 3 4 5 6)) (print x) (newline))
V p?íkladu také vidíme funkci gensym
, která slou?í ke generování náhodnych proměnnych, ke kterym nemá u?ivatel p?ístup. Slou?í to k ochraně p?ed tzv. ?symbol capture“, co? nastává v p?ípadě, kdy makro pot?ebuje nějakou vnit?ní pomocnou proměnnou. Pokud bychom nepou?ili náhodny symbol, mohl by u?ivatel k tomuto symbolu p?istupovat. ?patně definované makro dolist
by mohlo vypadat takto:
(define-macro (dolist-ugly instrukce . telo)
(let ((symbol (car instrukce))
(seznam (cadr instrukce)))
`(do ((iter ',seznam (cdr iter))
(,symbol (car ',seznam)))
((null? iter))
(set! ,symbol (car iter))
,@telo)))
;; P?íklad volání, kdy pocítíme symbol capture
(dolist-ugly (x (1 2 3 4)) (print iter))
; Vrátí: (1 2 3 4)(2 3 4)(3 4)(4) P?i?em? by to mělo zobrazit chybu na neexistující symbol.
P?íklady dal?ích u?ite?nych maker:
;; Makro when se chová podobně jako if, pouze nemá ?ádnou else větev.
;; V p?ípadě, ?e podmínka není splněna, automaticky vrátí false.
;; True větev ale m??e obsahovat více vyraz?.
(define-macro (when cond . true)
`(if ,cond
(begin
,@true)
#f))
; P?íklady pou?ití:
(when 1 2)
; 2
(when 1 (print 1) 2)
; 12
(when #f (print 1) 2)
; #f
;; Makro unless se chová opa?ně ne? makro when — neguje podmínku.
;; True větev se tudí? provede, není-li splněna p?edaná podmínka.
;; Prakticky to lze p?epsat jako (when (not <podmínka>) ...).
(define-macro (unless cond . true)
`(if (not ,cond)
(begin
,@true)
#f))
; P?íklady pou?ití:
(unless 1 2)
; #f
(unless 1 (print 5) 10)
; #f
(unless (= 1 2) (print 5) 10)
; 510
Hezkym p?íkladem jsou také podmíněné vyrazy pracující s pravděpodobností. Nap?íklad klasicky if upraveny tak, ?e namísto podmínky p?ebírá pouze procentuální vyjád?ení pravděpodobnosti, zda se provede true větev.
(define-macro (prob-if probability true false)
`(if (<= (+ 1 (random 100)) ,probability)
,true
,false))
; P?íklady pou?ití:
; (V 80 % p?ípad? se vrátí jedni?ka, ve 20 % dvojka.)
> (prob-if 80 1 2)
1
> (prob-if 80 1 2)
1
> (prob-if 80 1 2)
1
> (prob-if 80 1 2)
2
> (prob-if 80 1 2)
1
> (prob-if 80 1 2)
1
Streamy
[editovat | editovat zdroj]Pomocí maker m??eme také realizovat líné vyhodnocování, kdy se ve?keré argumenty funkcí budou vyhodnocovat líně, tj. a? kdy? budou t?eba. Díky tomuto m??eme naprogramovat if jako funkci. Líného vyhodnocení vyu?ijeme i p?i implementaci Stream?. Stream bude tvo?en te?kovymi páry, ale s tím rozdílem, ?e bude mít vyhodnocen pouze car ?ást, nikoli cdr. To realizujeme tím zp?sobem, ?e cdr ?ást ulo?íme jako proceduru, kterou vyhodnotíme a? p?i volání cdr streamu:
(define-macro (delay . expr)
`(lambda() ,@expr))
; P?íklady pou?ití
> (delay (print 100) (newline) (* 50 50))
#<procedure>
> (define d (delay (print 100) (newline) (* 50 50)))
> d
#<procedure:d>
> (d)
100
2500
Pomocí makra delay
jsme odlo?ili vyhodnocení vyraz? (print 100) (newline) (* 50 50)
a? do chvíle, kdy jsme to opravdu pot?ebovali — kdy? jsme zavolali (d)
. Zbytek u? nadefinujeme snadno:
(define-macro (cons-stream car-str cdr-str)
`(cons ,car-str
(delay ,cdr-str)))
(define stream-car car)
(define (stream-cdr stream)
((cdr stream)))
A nyní u? jen aplikace stream?:
;; Vrací nekone?ny proud jedni?ek
(define (ones)
(cons-stream 1 (ones)))
> (ones)
(1 . #<procedure>)
> (stream-cdr (ones))
(1 . #<procedure>)
> (stream-cdr (stream-cdr (stream-cdr (stream-cdr (ones)))))
(1 . #<procedure>)
;; Vrací nekone?ny proud p?irozenych ?ísel
(define (naturals n)
(cons-stream n (naturals (+ n 1))))
> (naturals 1)
(1 . #<procedure>)
> (stream-cdr (naturals 1))
(2 . #<procedure>)
> (stream-cdr (stream-cdr (stream-cdr (stream-cdr (naturals 1)))))
(5 . #<procedure>)
Související ?lánky
[editovat | editovat zdroj]Externí odkazy
[editovat | editovat zdroj]Obrázky, zvuky ?i videa k tématu Scheme na Wikimedia Commons
- oficiální stránky jazyka Scheme
- Interpret jazyka Scheme — DrScheme
- www.schemers.org – informace, reference jazyka,
- Skripta k Paradigmata programování — Scheme
- Teach yourself Scheme in fixnum days – velmi dobrá online u?ebnice Scheme
- P?edná?ky a cvi?ení pro podporu p?edmětu ?Alternativní metody programování“ – na TUL Liberec
- r6rs.org Archivováno 12. 8. 2013 na Wayback Machine.
- Online verze Lambda Papers (PDF format)
Reference
[editovat | editovat zdroj]- ↑ The Original 'Lambda Papers' [online]. [cit. 2025-08-14]. Dostupné v archivu po?ízeném dne 2025-08-14.
- ↑ R5RS Revised5 Report on the Algorithmic Language Scheme [online]. 2007-6-25. Dostupné online. (anglicky)
- ↑ R6RS R6RS.org [online]. [cit. 2025-08-14]. Dostupné v archivu po?ízeném dne 2025-08-14.