Organizacja przedmiotu Języki programowania (Programming language concepts) Krzysztof M. Ocetkiewicz pok. 205 email: Krzysztof.Ocetkiewicz@eti.pg.gda.pl konsultacje: czwartek 10:15-11.00, 13:15-14:00 projekt: mgr inż. Krzysztof M. Ocetkiewicz mgr inż. Tomasz Dobrowolski, p. 218, Tomasz.Dobrowolski@eti.pg.gda.pl K.M. Ocetkiewicz, 2008 WETI, PG 2 Treść przedmiotu Programowanie funkcjonalne Programowanie funkcjonalne. XSL, Haskell. Przekształcenia symboliczne. Rekurencja ogonowa, LISP. Programowanie w logice, PROLOG. Fakty, reguły, cele. Dopasowywanie i unifikacja. Programowanie z więzami (CLP) Metody definiowania składni. Semantyka denotacyjna Kolokwium II kładziemy nacisk na obliczanie funkcji matematycznych unikamy stanu i zmiennych danych K.M. Ocetkiewicz, 2008 WETI, PG 3 K.M. Ocetkiewicz, 2008 WETI, PG 4 Programowanie funkcjonalne Wyrażenia lambda Wyrażenia lambda Funkcje wyższego rzędu Funkcje czyste Częściowe wywołanie Currying Listy Operatory funkcjonalne Rekurencja K.M. Ocetkiewicz, 2008 WETI, PG 5 Wyrażenia lambda służą do zapisu funkcji anonimowych (bez nazwy; literały funkcyjne ) λ parametry. wartość funkcji Np.: suma = λ x y. x + y kwadrat = λ x. x * x K.M. Ocetkiewicz, 2008 WETI, PG 6
Funkcje wyższego rzędu Funkcje mogą być argumentem innej funkcji Wartością zwracaną może być funkcja Np.: Pochodna(F) = F Pochodna(λ x. x * x) = λ x. 2 * x Funkcje czyste Funkcje w matematycznym sensie Bez efektów ubocznych Dla tych samych parametrów zwracają zawsze to samo Czy rand() jest funkcją? czy zawsze rand(7) == rand(7)? K.M. Ocetkiewicz, 2008 WETI, PG 7 K.M. Ocetkiewicz, 2008 WETI, PG 8 Częściowe wywołanie (partial application) Nadanie wartości części argumentów funkcji Zamiast tworzyć funkcję dodajsiedem(x) = x + 7 map dodajsiedem lista Piszemy: map (+7) lista Currying Technika wywoływania funkcji, polegająca na przekazywaniu jej parametrów po jednym Każde wywołanie zwraca nową funkcję, która otrzymuje następny parametr: F(x, y, z) = ( ( F(x) )(y) )(z) K.M. Ocetkiewicz, 2008 WETI, PG 9 K.M. Ocetkiewicz, 2008 WETI, PG 10 Currying Jak, potrafiąc tworzyć wyłącznie funkcje jednoargumentowe, napisać funkcję dwuargumentową? dodaj(x) = λ y. x + y jak to działa? Listy struktura często używana w programowaniu funkcjonalnym pewna liczba elementów takiego samego typu dodaj(3)(5) = (dodaj(3))(5) = = (λ y. 3 + y)(5) = 3 + 5 = 8 K.M. Ocetkiewicz, 2008 WETI, PG 11 K.M. Ocetkiewicz, 2008 WETI, PG 12
Operacje na listach head (głowa) head [1, 2, 3, 4] = 1 tail (ogon) tail [1, 2, 3, 4] = [2, 3, 4] konstrukcja listy (złożenie listy z głowy i ogona) 1 : [2, 3, 4, 5] = [1, 2, 3, 4, 5] Operacje na listach concat (konkatenacja - scalenie dwóch list) concat( [1, 2, 3], [4, 5, 6] ) = [1, 2, 3, 4, 5, 6] K.M. Ocetkiewicz, 2008 WETI, PG 13 K.M. Ocetkiewicz, 2008 WETI, PG 14 Operatory funkcjonalne Mapowanie Redukcja (zwijanie) Filtrowanie Złożenie Zip, unzip K.M. Ocetkiewicz, 2008 WETI, PG 15 Mapowanie Zastosowanie danej funkcji na wszystkich elementach listy Wynikiem jest lista zawierająca otrzymane wartości funkcji L L x 2 F F( ) F( ) K.M. Ocetkiewicz, 2008 WETI, PG 16 F( ) Mapowanie Przykłady: map( [1, 2, 3, 4, 5], kwadrat) = [1, 4, 9, 16, 25] map( [1, -1, -3, 2, 7], abs) = [1, 1, 3, 2, 7] Funkcja może zwracać wartości innego typu: map( [1, 2, 3, 4, 5], tostring) = [ 1, 4, 9, 16, 25 ] map( [ [1, 2], [], [1, 2, 3], [1] ], length) = [2, 0, 3, 1] K.M. Ocetkiewicz, 2008 WETI, PG 17 Mapowanie Wynik możemy odrzucić, a funkcja może mieć efekty uboczne: map( [1, 2, 3, 4, 5], wypisznaekran) K.M. Ocetkiewicz, 2008 WETI, PG 18 1 2 3 4 5
Filtracja Wybór tylko tych elementów z listy, dla których predykat jest prawdziwy Wynikiem jest lista L P L x 2 P( ) = true P(x 2 ) = false P(x 3 ) = true K.M. Ocetkiewicz, 2008 WETI, PG 19 x 3 Filtracja Przykłady: filter( [1, 2, 3, 4, 5], parzyste) = [2, 4] filter( [1, -1, -3, 2, 7], dodatnie) = [1, 2, 7] Predykat - funkcja zwracająca wartość logiczną K.M. Ocetkiewicz, 2008 WETI, PG 20 Redukcja (zwijanie) Redukcja (zwijanie) Połączenie wszystkich elementów listy w jeden przy pomocy danej funkcji Wynikiem jest skalar (pojedyncza wartość) Argumentami są: lista, funkcja dwuargumentowa i wartość początkowa wart. pocz. F L x 2 x 3 F F F wynik K.M. Ocetkiewicz, 2008 WETI, PG 21 K.M. Ocetkiewicz, 2008 WETI, PG 22 Redukcja (zwijanie) Przykłady: reduce( [1, 2, 3, 4, 5], suma, 0) = 15 reduce( [1, 2, 3, 4, 5], iloczyn, 1) = 120 reduce( [1, 2, 3, 4, 5], max, - ) = 5 reduce( [ [1], [2, 3], [4, 5, 6], [], [7] ], concat, [] ) = [1, 2, 3, 4, 5, 6, 7] Redukcja (zwijanie) Drugi argument funkcji nie musi być tego samego typu co wartość początkowa i pierwszy argument: dolacznapis(a, b) = a + + tostring(b) reduce( [1, 2, 3, 4, 5], dolacznapis, ) = 1 2 3 4 5 K.M. Ocetkiewicz, 2008 WETI, PG 23 K.M. Ocetkiewicz, 2008 WETI, PG 24
Redukcja (zwijanie) W niektórych językach istnieją dwa warianty redukcji od lewej do prawej od prawej do lewej Różnica - gdy funkcja nie jest łączna: Złożenie Złożenie funkcji (w sensie matematycznym) (F G)(x) = F(G(x)) Norma(x) = sqrt(reduce(map(x, kwadrat), suma, 0)) reduceltor( [1, 2, 3], minus, 0) = ((0-1) - 2) - 3 = -6 reducertol( [1, 2, 3], minus, 0) = 1 - (2 - (3-0)) = 2 K.M. Ocetkiewicz, 2008 WETI, PG 25 K.M. Ocetkiewicz, 2008 WETI, PG 26 Zip Zip - połączenie dwóch list w jedną listę par elementów L 1 L x 2 L 2 y 1 y 2 y n (, y 1 ) (x 2, y 2 ) K.M. Ocetkiewicz, 2008 WETI, PG 27 (, y n ) Zip Przykład: iloczyn( (a, b) ) = a * b x iloczynskalarny(x, y) = x 2 y y 1 y 2 y n zip = reduce(map(zip(x, y), iloczyn), suma, 0) (, y 1 ) (x 2, y 2 ) (, y n ) map * y 1 x 2 * y 2 K.M. Ocetkiewicz, 2008 WETI, PG 28 * y n reduce iloczyn skalarny Unzip Unzip - operacja odwrotna do zip - rozłożenie listy par na parę list L (, y 1 ) (x 2, y 2 ) (, y n ) unzip( [ (1, 2), (3, 4), (5, 6) ] ) = ( [1, 3, 5], [2, 4, 6] ) L 1 x 2 L 2 y 1 y 2 y n Rekurencja Najczęstsza metoda wykonywania iteracji map([], F) = [] map(l, F) = F(head(L)) : map(tail(l), F) reduceltor([], F, Z) = Z reduceltor(l, F, Z) = reduce(tail(l), F, F(Z, head(l)) reducertol([], F, Z) = Z reducertol(l, F, Z) = F(head(L), reduce(tail(l), F, Z)) K.M. Ocetkiewicz, 2008 WETI, PG 29 K.M. Ocetkiewicz, 2008 WETI, PG 30
Programowanie funkcjonalne a XSL Argument funkcjonalny Listy Operatory funkcjonalne Złożenie funkcji Argument funkcjonalny Najbliżej funkcji w XSL jest szablon Ale: <xsl:call-template name= $fn /> BŁĄD K.M. Ocetkiewicz, 2008 WETI, PG 31 K.M. Ocetkiewicz, 2008 WETI, PG 32 Argument funkcjonalny Argument funkcjonalny Rozwiązanie:referencje do szablonów: <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/xsl/transform" xmlns:f1="f:mul2-template"> <xsl:template match= "*[namespace-uri()=" f:mul2-template ]"> <xsl:param name="arg1"/> <xsl:value-of select="2*$arg1"/> <xsl:variable name="times2" select="document( )/*/f1:*[1]" /> <f1:f1/> </xsl:stylesheet> K.M. Ocetkiewicz, 2008 WETI, PG 33 Wywołanie: <xsl:template name="apply"> <xsl:param name="pfun"/> <xsl:param name="pvalue"/> <xsl:apply-templates select="$pfun"> <xsl:with-param name="arg1" select="$pvalue"/> <xsl:call-template name="apply"> <xsl:with-param name="pfun" select="$times2"/> <xsl:with-param name="pvalue" select="4"/> </xsl:call-template> K.M. Ocetkiewicz, 2008 WETI, PG 34 Jak to działa? Przestrzeń nazw o unikalnej nazwie (f:mul2_template) Szablon (tylko jeden) przetwarzający tę przestrzeń nazw (nasza funkcja) W momencie wywołania stosujemy szablony na stworzonej przestrzeni nazw Listy Jako XML-owe drzewa: <lista> <el>element_1</el> <el>element_2</el> <el>element_n</el> </lista> K.M. Ocetkiewicz, 2008 WETI, PG 35 K.M. Ocetkiewicz, 2008 WETI, PG 36
Mapowanie Mapowanie <xsl:template name="map"> <xsl:param name="pfun"/> <xsl:param name="plist"/> <xsl:for-each select="$plist"> <xsl:copy> <xsl:apply-templates select="$pfun"> <xsl:with-param name="arg1" select="."/> </xsl:copy> </xsl:for-each> <lista> <el>1</el> <el>2</el> <el>3</el> <el>4</el> </lista> <xsl:call-template name="map"> <xsl:with-param name="pfun select="$times2"/> <xsl:with-param name="plist select="/lista/el"/> </xsl:call-template> 2468 K.M. Ocetkiewicz, 2008 WETI, PG 37 K.M. Ocetkiewicz, 2008 WETI, PG 38 Redukcja Redukcja <xsl:template name="reduce"> <xsl:param name="pfun"/> <xsl:param name="pzero"/> <xsl:param name="plist"/> <xsl:choose> <xsl:when test="not($plist)"> <xsl:copy-of select="$pzero"/> </xsl:when> <xsl:otherwise> <xsl:variable name="funresult"> <xsl:apply-templates select="$pfun"> <xsl:with-param name="arg1" select="$pzero"/> <xsl:with-param name="arg2" select="$plist[1]"/> </xsl:variable> <xsl:call-template name="reduce"> <xsl:with-param name="pfun" select="$pfun"/> <xsl:with-param name="pzero" select="$funresult"/> <xsl:with-param name="plist" select="$plist[position() > 1]"/> </xsl:call-template> </xsl:otherwise> </xsl:choose> K.M. Ocetkiewicz, 2008 WETI, PG 39 <lista> <el>1</el> <el>2</el> <el>3</el> <el>4</el> </lista> <xsl:template match="*[]"> <xsl:param name = "arg1" /> <xsl:param name = "arg2" /> <xsl:value-of select = $arg1+$arg2" /> <xsl:variable name = add" select = "" /> <xsl:call-template name= reduce"> <xsl:with-param name="pfun select="$add"/> <xsl:with-param name="plist select="/lista/el"/> <xsl:with-param name="pzero select="0"/> </xsl:call-template> K.M. Ocetkiewicz, 2008 WETI, PG 40 10 Filtrowanie Filtrowanie <xsl:template name="filter"> <xsl:param name="pfun" select="/.."/> <xsl:param name="plist"/> <xsl:for-each select="$plist"> <xsl:variable name="test"> <xsl:apply-templates select="$pfun"> <xsl:with-param name="arg1" select="."/> </xsl:variable> <xsl:if test="string($test)='true'"> <xsl:copy-of select="."/> </xsl:if> </xsl:for-each> <lista> <el>1</el> <el>2</el> <el>3</el> <el>4</el> </lista> <xsl:template match="*[]"> <xsl:param name = "arg1" /> <xsl:value-of select = "number($arg1)!=3" /> <xsl:variable name = "ne3" select = "" /> <xsl:call-template name= filter"> <xsl:with-param name="pfun select="$ne3"/> <xsl:with-param name="plist select="/lista/el"/> </xsl:call-template> 124 K.M. Ocetkiewicz, 2008 WETI, PG 41 K.M. Ocetkiewicz, 2008 WETI, PG 42
Złożenie funkcji <!-- xmlns:ext="http://exslt.org/common" --> <xsl:template name="compose"> <xsl:param name="pfun1"/> <xsl:param name="pfun2"/> <xsl:param name="par"/> <xsl:variable name= iv"> <xsl:apply-templates select="$pfun1"> <xsl:with-param name="arg1" select="$par"/> </xsl:variable> <xsl:apply-templates select="$pfun2"> <xsl:with-param name="parg1" select="ext:node-set($iv)/node()" /> K.M. Ocetkiewicz, 2008 WETI, PG 43 Źródła http://fxsl.sourceforge.net Dimitre Novatchev: Functional programming in XSLT using FXSL library (Extreme Markup Languages 2003) Dimitre Novatchev: Higher-Order Functional Programming with XSLT 2.0 and FXSL (Extreme Markup Languages 2006) K.M. Ocetkiewicz, 2008 WETI, PG 44 Język Haskell Język czysto funkcjonalny Bardzo blisko matematycznego formalizmu http://www.haskell.org Zmienne Operator przypisania = nadaje wartość symbolowi Raz nadana wartość nie zmienia się przez cały czas życia symbolu Jak w matematyce: pi = 3.14159 Brak zmiennej jako pudełka na wartość K.M. Ocetkiewicz, 2008 WETI, PG 45 K.M. Ocetkiewicz, 2008 WETI, PG 46 Listy Lista ma postać: [elem1, elem2,, elemn] Wszystkie elementy muszą być tego samego typu Łańcuch znakowy jest jednocześnie listą znaków Listy Głowa listy: head np.: head [1, 2, 3, 4] = 1 Ogon listy: tail np.: tail [1, 2, 3, 4] = [2, 3, 4] Konstrukcja listy: dwukropek np.: 1 : [2, 3, 4] = [1, 2, 3, 4] 1 : 2 : 3 : [4] = [1, 2, 3, 4] K.M. Ocetkiewicz, 2008 WETI, PG 47 K.M. Ocetkiewicz, 2008 WETI, PG 48
Listy Konkatenacja: ++ np.: [1, 2] ++ [3, 4] = [1, 2, 3, 4] np.: abc ++ def = abcdef Funkcje Definicja ma postać: nazwa parametry = wyrażenie np.: add x y = x + y Złożone wyrażenia: hypot x y = let x2 = x * x in sqrt (x2 + y2) where y2 = y * y K.M. Ocetkiewicz, 2008 WETI, PG 49 K.M. Ocetkiewicz, 2008 WETI, PG 50 Funkcje Pattern matching: potega _ 0 = 1 potega a 1 = a potega a b = a * potega a (b - 1) sign x x > 0 = 1 x < 0 = -1 otherwise = 0 mapuj _ [] = [] mapuj f x:xs = (f x) : mapuj (f xs) Funkcje lambda Funkcje anonimowe mają postać: np. \ argumenty -> wyrażenie \ x y -> x*x + y*y K.M. Ocetkiewicz, 2008 WETI, PG 51 K.M. Ocetkiewicz, 2008 WETI, PG 52 Currying Wszystkie funkcje wołane są za pomocą curryingu: f x y z = ( (f x) y) z Przez co: listadokwadratu = map (\ x -> x*x) Operatory Potęgowanie: ^ (np. 2^32) Złożenie funkcji:. (np. h = g. f) Wywołanie funkcji: $ (np. f $ par) dodaj 3 sin 4 =( (dodaj 3) sin) 4 dodaj 3 $ sin 4 = dodaj 3 (sin 4) K.M. Ocetkiewicz, 2008 WETI, PG 53 K.M. Ocetkiewicz, 2008 WETI, PG 54
Operatory Operatory infiksowe możemy traktować jak funkcje: np.: (+) 3 2 = 5 Funkcji dwuargumentowych możemy używać jak operatorów np.: add x y = x + y 3 `add` 2 = 5 Operatory funkcjonalne map funkcja lista np.: map (+2) [1, 2, 3] = [3, 4, 5] filter predykat lista np. filter (>0) [1, -2, -3, 4] = [1, 4] foldl/foldr funkcja zero lista np.: foldl (+) 0 [1, 2, 3] = 6 K.M. Ocetkiewicz, 2008 WETI, PG 55 K.M. Ocetkiewicz, 2008 WETI, PG 56 Częściowe wywołanie Programowanie funkcjonalne np.: dodaj a b = a + b odejmij a b = a - b (dodaj 3) (odejmij 2) (`odejmij` 2) (2 `odejmij`) (3 + ) (2 - ) ( / 4) kładziemy nacisk na obliczanie funkcji matematycznych unikamy stanu i zmiennych danych norma = sqrt. foldl (+) 0. map (\x -> x*x) norma [3, 4] = 5 K.M. Ocetkiewicz, 2008 WETI, PG 57 K.M. Ocetkiewicz, 2008 WETI, PG 58