Cvičení 6 --------- RIZIKA MAKER ============ - vícenásobné vyhodnocení - (nechtěné) zakrytí symbolu = symbol capture PR: (define-macro square (lambda (x) `(* ,x ,x))) (square 5) => (* 5 5) (define a 10) (square (begin (set! a 2) 3)) => ?? Co se s tím dá dělat? - zapamatujeme si výsledek vyhodnocení x (define-macro square (lambda (x) `(let ((tmp ,x)) (* tmp tmp)))) Potenciálně ale může nastat problém jinde např.: ------------------------------------------------ (define-macro swap (lambda (x y) `(let ((tmp ,x)) (set! ,x ,y) (set! ,y tmp)))) Kde je problém? (define tmp 10) (define my 2) (swap tmp my) =EXP=> ?? tmp => ?? Reseni, vygenerovani jednoznacneho symbolu v letu (nicim jinym nepouziteho - jedinecny nazev promenne), to umi procedura gensym PR: (gensym) g4750 (gensym) g4781 (define-macro swap2 (lambda (x y) (let ((symb-name (gensym))) `(let ((,symb-name ,x)) (set! ,x ,y) (set! ,y ,symb-name)))) ZNOVU: (define tmp 10) (define my 2) (swap tmp my) =EXP=> ?? tmp => ?? DU: napiste makro dotuplets, s touto syntaxi (2 body) POZOR! nesmi dojit k symbol capture ani k vícenásobnému vyhodnoceni, jinak 0 bodu! (dotuplets (n (x lst)) . body) rozdeli seznam na n-tice a projde je jako foreach ale po n-ticich (ty se postupne budou objevovat v x), pokud nebude delka seznamu delitelna n, skonci chybou n ... pocet prvku v tuplu (ntici) x ... promenna pres kterou iterujeme lst ... seznam, ze ktereho vybirame tuply zleva do prava body ... telo, ktera se zavola pri vytvoreni kazdeho tuplu, krome posledniho, musi byt videt promenna x procedura vraci hodnotu posledniho vyhodnoceni PR: (dotuplets (3 (x '(1 2 3 4 5 6 7))) (display x) x) => chyba PR: (dotuplets (3 (x '(1 2 3 4 5 6 7 8 9))) (display x) x) (1 2 3) (4 5 6) (7 8 9) => (7 8 9)