Ćwiczenia z wyliczania wartości funkcji 4 października 2011 1 Wprowadzenie Wyliczanie wartości wyrażenia nie jest sprawą oczywistą, szczególnie jeżeli chodzi o aplikację funkcji. Poniższy tekst nie jest żadnym wyznacznikiem poprawnego sposobu, a jedynie pomocą w nauce. W szczególności nie istnieje metoda najlepsza, a specyficzne przypadki mogą się różnić między programami, kompilatorami, systemami matematycznymi, etc. Dla przykładu, najprostsza definicja funkcji stałej wykonana w dwóch różnych interpreterach na serwerze students: [dl26088@students:~/nauka/wpf]$ ocaml Objective Caml version.12.1 # let f x = 42 val f : a -> int = <fun> # f (0/0) Exception: Division_by_zero. [dl26088@students:~/nauka/wpf]$ ghci GHCi, version 7.2.1: http://www.haskell.org/ghc/ :? for help Loading package ghc-prim... linking... done. Loading package integer-gmp... linking... done. Loading package base... linking... done. Loading package ffi-1.0... linking... done. Prelude> let f x = 42 Prelude> f (0/0) 42 Temat ten zostanie poruszony w przyszłości, a w większym zakresie i dokładności na przedmiocie traktującym o semantyce języków programowania. 2 Funkcje i operatory Operatory takie jak dodawanie, odejmowanie, mnożenie, iloczyn skalarny, iloczyn wektorowy, produkt kartezjański również można określić jako odpowiednie funkcje. Jedyna różnica jest taka, że się je specyficznie zapisuje w środku, natomiast operacje te również mają swoją dziedzinę i zbiór wartości. W matematyce argumenty funkcji najczęściej otacza się nawiasami f(x) ale nie jest to konieczne, wszystko zależy od czytelności sin α = sin(α) f(x, y, z) = f( x, y, z ) 1
Jeżeli mamy definicję postaci f(napis 1 ) = napis 2 to napis 1 nazywamy argumentem/argumentami funkcji, a napis 2 jest jej wzorem. W tym tekście stosuję konwencję 1 zapisu, w której powyższa definicja może przybrać postać f = napis 1 napis 2 natomiast zbędne nawiasy są opuszczane. Ponadto zmienne użyte w definicji funkcji (o ile stosowane konsekwentnie i nie powodując kolizji) nie mają znaczenia, np. funkcje f = x, y x + y oraz g = a, b a + b to te same funkcje, natomiast h = x, y y + x jest już innym odwzorowaniem (gdyż dodawanie niekoniecznie musi być określone jako przemienne). W przypadku operatorów ważna jest kolejność działań, będziemy przyjmować, że zastosowanie argumentu do funkcji (jeżeli kolejność nie została zmieniona przez nawiasy) wykonuje się przed innymi działaniami, np. Część operatorów jest łączna lewostronnie, np. sin α + β = (sin α) + β 10 1 2 4 = ((((10 1) 2) ) 4) natomiast inne są łączne prawostronnie, np. ( ( 4 5 ) ) 2 45 = 2 Aplikacje są lewostronne, tzn. Natomiast definicje są prawostronne, tzn. f x y z = (((f x)y)z) x y z x + y z = x (y (z (x + y z))) Operator oznacza złożenie funkcji (f g)(x) = f(g(x)) i jest łączny, tzn. nie ma znaczenia jak zgrupowane wyrażenie ponawiasujemy (f g) h = x f(g(h(x))) = f (g h). Przykłady id(x) = x id = x x f 1 (x) = 2 x f 1 (5) = 2 x x=5 = 2 5 = 10 f 2 = y 2 y f 2 = f 1 f 2 e = 2 y y=e = 2 e = 2e f = g g 50 f f 2 = (g g 50)(y 2 y) = (g 50) g=y 2 y = (y 2 y)(50) = 2 y y=50 = 2 50 = 100 1 warto zaznaczyć, że w matematyce i informatyce istnieje wiele konwencji, a zapis używany w tym dokumencie nie należy do tych najczęściej stosowanych 2
f 4 = x y x y = x (y x y) f 4 2 = (x y x y) x=2 = y 2 y = f 1 = f 2 f 4 2 e = (f 4 2)e = f 1 e = 2e f (f 4 2) = 100 f 4 2 f = (f 4 2) f jest wyrażeniem niepoprawnym, bo nie jest określone mnożenie funkcji przez liczbę 2 f f 4 2 (f (f 4 2)) = (f 4 2) (f (f 4 2)) = f 1 (f f 1 ) = f 1 100 = 200 compose = f g x f(g x) compose f g = f g compose(f)(g)(x) = f(g x) compose f g x = f(g x) (cos sin)(0) = cos(sin 0) = 1 compose cos sin = (compose cos) sin = (f g x f(g x)) f=cos sin = (g x cos(g x)) sin = (x cos(g x)) g = sin = x cos(sin x) compose cos sin 0 = 1 D f = f D sin = cos D sin 0 = cos 0 = 1 D (x 2 + x + 1) jest błędnym wyrażeniem, bo x 2 + x + 1 nie jest funkcją D (x x 2 + x + 1) = z 2z + 1 D (y y 2 + y + 1) (5) = (x 2x + 1)(5) = (2x + 1) x=5 = 2 5 + 1 = 11 integer f = f(x) dx f() + 4 f(0) + f(1) simpson f = integer(z z 2 + z + 1) = = (z z 2 + z + 1)(x) dx = ( x x 2 + x + 1 dx = + x2 2 + x (z 2 + z + 1) z=x dx ) 1 = 8 simpson(z z 2 + z + 1) = (z z2 + z + 1)() + 4 (z z 2 + z + 1)(0) + (z z 2 + z + 1)(1) = (a a2 + a + 1)() + 4 (b b 2 + b + 1)(0) + (c c 2 + c + 1)(1) = (a2 + a + 1) a= + 4 (b 2 + b + 1) b=0 + (c 2 + c + 1) c=1 = 1 + 4 1 + = 8
4 Ćwiczenia Niech inc x = x + 1 add x y = x + y two x = 2 id x = x ti x = (x, ) pair 2 a b f = f a b prawda x y = x falsz x y = y pair a b = a, b fst a, b = a snd a, b = b app f x = f x ppa x f = f x compose f g x = f (g x) nie f a b = f b a i f g a b = f (g a b) b lub f g a b = f a (g a b) xor f g a b = f (g b a) (g a b) div x y exit = if y 0 then (k k (x/y)) else exit 42 callcc f k = f (c d k c) k Oblicz 1. two inc 2. pair. fst pair 2 4. compose snd (pair 42) 5. nie pair 6. app two inc 7. ppa pair 8. pair 2 10 1 9. pair 2 10 1 fst 10. pair 2 10 1 add 11. nie (pair 2 2) fst 12. nie (pair 2 42) falsz 1. nie (pair 2 inc, two ) fst 14. prawda 1 0 15. falsz 1 0 16. nie prawda 1 0 17. i prawda falsz 1 0 18. xor falsz prawda 19. x y nie (lub (nie x) (nie y)) 20. callcc (div 8 4) id 21. callcc (div 8 4) 22. callcc (div 8 0) inc 2. callcc (div 8 0) 4
5 Wyniki 1. two inc = 2 2. pair = u (, u). fst pair 2 = two 4. compose snd (pair42) = id 5. nie pair = ti 6. app two inc = 2 7. ppa pair = u (, u) 8. pair 2 10 1 = f f 10 1 9. pair 2 10 1 fst jest niepoprawne, bo 10 nie należy do dziedziny fst (występuje podczas obliczania fst 10 1. 10. pair 2 10 1 add = 11 11. nie (pair 2 2) fst jest niepoprawne, bo 2 nie należy do dziedziny fst 12. nie (pair 2 42) falsz = id 1. nie (pair 2 inc, two ) fst = inc 14. prawda 1 0 = 1 15. falsz 1 0 = 0 16. nie prawda 1 0 = 0 17. i prawda falsz 1 0 = 0 18. xor falsz prawda = prawda 19. x y nie (lub (nie x) (nie y)) = i 20. callcc (div 8 4) id = 2 21. callcc (div 8 4) = t t 2 22. callcc (div 8 0) inc = 4 2. callcc (div 8 0) = t t 42 5