TIEA341 Funktio-ohjelmointi 1, kevät 2008 Luento 11 Antti-Juhani Kaijanaho Jyväskylän yliopisto Tietotekniikan laitos 21. tammikuuta 2008
Listakomprehensio Uusi tapa luoda (ja muokata) listoja: [ lauseke tarkenne 1,..., tarkenne n ] tarkenne voi olla: hahmo <- listalauseke (generaattori) kukin hahmossa mainittu muuttuja näkyy myöhemmissä tarkenteissa sekä pystyviivan vasemmalla puolella nuolen oikealla puolella olevan lausekkeen on oltava listatyyppiä; kutakin ko. lausekkeen arvon alkiota sovitetaan vuorollaan hahmoon ehtolauseke (vahti) let määritelmäjoukko kukin määritelty muuttuja näkyy myöhemmissä tarkenteissa sekä pystyviivan vasemmalla puolella
Esimerkkejä [ x^2 x < [ 1.. ], x mod 2 == 1 ] Lista kaikista parittomien lukujen neliöistä. c a r t e s i a n xs ys = [ ( x, y ) x < xs, y < ys ] Funktio, joka muodostaa kahden listan karteesisen tulon. Idea: iteroidaan generaattoreissa mainittujen listojen läpi ja raakataan pois ne, jotka vahdit hylkäävät, ja muodostetaan kullakin ei-hylätyllä kierroksella uusi alkio tuloslistaan.
Kielioppimakeinen [ e True ] = [ e ] [ e q ] = [ e q, True ] [ e b, Q ] = if b then [ e Q ] else [] [ e p <- l, Q ] = let ok p = [ e Q ] ; ok _ = [] in concatmap ok l (missä ok on uusi nimi) [ e let decls, Q ] = let decls in [ e Q ] Missä e on lauseke, q on jokin tarkennin, Q on tarkentimien jono, b on ehtolauseke, p on hahmo, l on listalauseke ja decls on määritelmäjoukko.
Tyyppiluokat Muistathan: (+) : : Num a => a > a > a (==) : : Eq a => a > a > Bool show : : Show a => a > String fromintegral : : (Num b, I n t e g r a l a ) => a > b Num, Eq, Show ja Integral ovat tyyppiluokkia osa tyypeistä kuuluu Num:iin, osa ei Num a, Eq a, Show a ja (Num b, Integral a) ovat konteksteja konteksti =>tyyppi tarkoittaa, että kyseinen tyyppi on voimassa silloin, kun konteksti pätee
Vakiokirjaston tyyppiluokat: Eq c l a s s Eq a where (==) : : a > a > Bool (/=) : : a > a > Bool x /= y = not ( x == y ) x == y = not ( x /= y ) Tyyppi a kuuluu luokkaan Eq, jos ja vain jos ko. tyypille on määritelty funktiot (==) :: a > a > Bool ja (/=) :: a > a > Bool. Mikäli funktiota (/=) ei ole määritelty, se määritellään automaattisesti luokkaan Eq kuuluvilla tyypeillä seuraavasti: x /= y = not (x == y). Mikäli funktiota (==) ei ole määritelty, se määritellään automaattisesti luokkaan Eq kuuluvilla tyypeillä seuraavasti: x == y = not (x /= y).
Vakiokirjaston tyyppiluokat: Ord d a t a O r d e r i n g = LT EQ GT c l a s s Eq a => Ord a where compare : : a > a > O r d e r i n g ( <), (<=), (>=), (>) : : a > a > B o o l max, min : : a > a > a compare x y x == y = EQ x <= y = LT o t h e r w i s e = GT x <= y = compare x y /= GT x < y = compare x y == LT x >= y = compare x y /= LT x > y = compare x y == GT max x y x <= y = y o t h e r w i s e = x min x y x <= y = x o t h e r w i s e = y class Eq a =>Ord a tarkoittaa, että vain Eq-luokkaan kuuluva tyyppi voi kuulua Ord-luokkaan.
Vakiokirjaston tyyppiluokat: Show t y p e ShowS = S t r i n g > S t r i n g c l a s s Show a where showsprec : : I n t > a > ShowS show : : a > S t r i n g s h o w L i s t : : [ a ] > ShowS s h o w s P r e c _ x s = show x ++ s show x = s h o w s P r e c 0 x "" s h o w L i s t [ ] = s h o w S t r i n g " [ ] " s h o w L i s t ( x : x s ) = showchar [. shows x. s h o w l x s where s h o w l [ ] = showchar ] s h o w l ( x : x s ) = showchar,. shows x. s h o w l x s
ShowS ShowS on näppärä temppu, jolla kierretään se, että (++) on tehoton, kun merkkijonoa kasataan lisäämällä jatkuvasti uutta kamaa loppuun ShowS-tyyppinen arvo edustaa merkkijonoa se on funktio, joka lisää edustamansa merkkijonon parametrina saamansa merkkijonon eteen (.) toimii ShowS-merkkijonojen katenoijana Vakiokirjastossa myös: showchar : : Char > ShowS showstring : : String > ShowS shows : : (Show a ) => a > ShowS
showsprec showsprec : : Show a => I n t > a > ShowS muuttaa annetun vekottimen merkkijonoksi huomioiden presedenssitasot ensimmäinen parametri kertoo nykyisen presedenssitason jos tulostettavan vekottimen presedenssi on matalampi kuin nykyisen presedenssitason, merkkijonon ympärille tulee sulut
showlist showlist : : Show a => [ a ] > ShowS käyttää normaalisti normaalia listasyntaksia mahdollistaa erikoisten esitysten käyttämisen esim. String-tyypillä tämä on määritelty uudestaan
Vakiokirjaston tyyppiluokat: Read t y p e ReadS a = S t r i n g > [ ( a, S t r i n g ) ] c l a s s Read a where r e a d s P r e c : : I n t > ReadS a r e a d L i s t : : ReadS [ a ] r e a d L i s t =... l e x : : ReadS S t r i n g l e x =.. r e a d s : : ( Read a ) => ReadS a r e a d s = r e a d s P r e c 0 r e a d : : ( Read a ) => S t r i n g > a r e a d s = c a s e [ x ( x, t ) < r e a d s s, ( "", "" ) < l e x t ] o f [ x ] > x [ ] > e r r o r " P r e l u d e. r e a d : no p a r s e " _ > e r r o r " P r e l u d e. r e a d : ambiguous p a r s e "
ReadS on jäsennysfunktioiden tyyppi: otetaan merkkijono ja palautetaan lista mahdollisista (osittaisista) jäsennyksistä (ja mitä jäi jäljelle) readsprec on showsprec n vastakohta readslist on readsprec n vastakohta reads ja read ovat hyödyllisiä apufunktioita, joita ei määritellä kullekin tyypille erikseen
Vakiokirjaston tyyppiluokat: Enum c l a s s Enum a where s u c c, p r e d : : a > a toenum : : I n t > a fromenum : : a > I n t enumfrom : : a > [ a ] [ n.. ] enumfromthen : : a > a > [ a ] [ n, n.. ] enumfromto : : a > a > [ a ] [ n.. m] enumfromthento : : a > a > a > [ a ] [ n, n.. m] s u c c = toenum. (+1). fromenum p r e d = toenum. ( s u b t r a c t 1). fromenum enumfrom x = map toenum [ fromenum x.. ] enumfromto x y = map toenum [ fromenum x.. fromenum y ] enumfromthen x y = map toenum [ fromenum x, fromenum y.. ] enumfromthento x y z = map toenum [ fromenum x, fromenum y.. fromenum z ] lueteltavissa olevien tyyppien luokka
Vakiokirjaston tyyppiluokat: Bounded c l a s s Bounded a where minbound : : a maxbound : : a rajoitettujen tyyppien luokka
Vakiokirjaston tyyppiluokat: Num c l a s s (Eq a, Show a ) => Num a where (+), ( ), ( ) : : a > a > a negate : : a > a abs, signum : : a > a frominteger : : Integer > a x y = x + negate y negate x = 0 x Kokonaislukuvakiot kulkevat implisiittisesti frominteger n kautta.
Vakiokirjaston tyyppiluokat: Real c l a s s (Num a, Ord a ) => Real a where torational : : a > Rational reaalilukuja approksimoivien lukutyyppien luokka jokainen approksimoiva luku on rationaaliluku (torational on tarkka muunnos)
Vakiokirjaston tyyppiluokat: Integral c l a s s ( R e a l a, Enum a ) => I n t e g r a l a where quot, rem : : a > a > a d i v, mod : : a > a > a quotrem, divmod : : a > a > ( a, a ) t o I n t e g e r : : a > I n t e g e r n quot d = q where ( q, r ) = quotrem n d n rem d = r where ( q, r ) = quotrem n d n div d = q where ( q, r ) = divmod n d n mod d = r where ( q, r ) = divmod n d divmod n d = i f signum r == signum d then ( q 1, r+d ) e l s e qr where qr@ ( q, r ) = quotrem n d
Vakiokirjaston tyyppiluokat: Fractional c l a s s (Num a ) => F r a c t i o n a l a where ( / ) : : a > a > a r e c i p : : a > a fromrational : : Rational > a r e c i p x = 1 / x x / y = x r e c i p y
Vakiokirjaston tyyppiluokat: Floating c l a s s ( F r a c t i o n a l a ) => Floating a where pi : : a exp, log, sqrt : : a > a ( ), logbase : : a > a > a sin, cos, tan : : a > a asin, acos, atan : : a > a sinh, cosh, tanh : : a > a asinh, acosh, atanh : : a > a x y = exp ( log x y ) logbase x y = log y / log x s qrt x = x 0. 5 tan x = s i n x / cos x tanh x = sinh x / cosh x
Vakiokirjaston tyyppiluokat: RealFrac c l a s s ( R e a l a, F r a c t i o n a l a ) => R e a l F r a c a where p r o p e r F r a c t i o n : : ( I n t e g r a l b ) => a > ( b, a ) t r u n c a t e, r o u n d : : ( I n t e g r a l b ) => a > b c e i l i n g, f l o o r : : ( I n t e g r a l b ) => a > b t r u n c a t e x = m where (m,_) = p r o p e r F r a c t i o n x r o u n d x = l e t ( n, r ) = p r o p e r F r a c t i o n x m = i f r < 0 t h e n n 1 e l s e n + 1 i n c a s e signum ( a b s r 0. 5 ) o f 1 > n 0 > i f e v e n n t h e n n e l s e m 1 > m c e i l i n g x = i f r > 0 t h e n n + 1 e l s e n where ( n, r ) = p r o p e r F r a c t i o n x f l o o r x = i f r < 0 t h e n n 1 e l s e n where ( n, r ) = p r o p e r F r a c t i o n x properfraction palauttaa luvun kokonaisosan ja desimaaliosan toisistaan erotettuina
Vakiokirjaston tyyppiluokat: RealFloat c l a s s ( R e a l F r a c a, F l o a t i n g a ) => R e a l F l o a t a where f l o a t R a d i x : : a > I n t e g e r f l o a t D i g i t s : : a > I n t f l o a t R a n g e : : a > ( I n t, I n t ) d e c o d e F l o a t : : a > ( I n t e g e r, I n t ) e n c o d e F l o a t : : I n t e g e r > I n t > a e x p o n e n t : : a > I n t s i g n i f i c a n d : : a > a s c a l e F l o a t : : I n t > a > a isnan, i s I n f i n i t e, i s D e n o r m a l i z e d, i s N e g a t i v e Z e r o, i s I E E E : : a > B o o l a t a n 2 : : a > a > a e x p o n e n t x = i f m == 0 t h e n 0 e l s e n + f l o a t D i g i t s x where (m, n ) = d e c o d e F l o a t x s i g n i f i c a n d x = e n c o d e F l o a t m ( f l o a t D i g i t s x ) where (m,_) = d e c o d e F l o a t x s c a l e F l o a t k x = e n c o d e F l o a t m ( n+k ) where (m, n ) = d e c o d e F l o a t x a t a n 2 y x =...
Tyypin määritteleminen osaksi luokkaa instance Eq Char where c == c = fromenum c == fromenum c instance Ord Char where c <= c = fromenum c <= fromenum c Char kuuluu Eq-tyyppiluokkaan, ja samalla määritellään vaadittu funktio c == c = fromenum c == fromenum c. Char kuuluu Ord-tyyppiluokkaan, ja samalla määritellään vaadittu funktio c <= c = fromenum c <= fromenum c.
määrittelemättä jätetyt funktiot määritellään class-määrittelyssä esitetyllä tavalla (ns. oletusmääritelmä) jos funktiolla ei ole oletusmääritelmää, se on pakko määritellä jos funktio määritellään instance-määrittelyssä, sen mahdollinen oletusmääritelmä sivuutetaan
Esimerkki: Eq (FiniteMap k d) i n s t a n c e ( Eq k, Eq d ) => Eq ( FiniteMap k d ) where EmptyFM == EmptyFM = True (NonEmptyFM l t k d gt ) == (NonEmptyFM l t k d gt ) = k == k && d == d && l t == l t && gt == gt _ == _ = F a l s e
Esimerkki: Show Expr i n s t a n c e Show Expr where s h o w s P r e c 1 = showscmp s h o w s P r e c 2 = showsadd s h o w s P r e c 3 = showsmul s h o w s P r e c 4 = showspow s h o w s P r e c 5 = showsunary s h o w s P r e c n n >= 6 = s h o w s P r i m a r y n <= 0 = showsexpr showsexpr : : Expr > ShowS showsexpr = showscmp...
... Esimerkki: Show Expr showscmp : : Expr > ShowS showscmp ( e1 :==: e2 ) = showsadd e1. s h o w S t r i n g " == ". showsadd e2 showscmp ( e1 : /=: e2 ) = showsadd e1. s h o w S t r i n g " /= ". showsadd e2 showscmp ( e1 :<=: e2 ) = showsadd e1. s h o w S t r i n g " <= ". showsadd e2 showscmp ( e1 :>=: e2 ) = showsadd e1. s h o w S t r i n g " >= ". showsadd e2 showscmp ( e1 : <: e2 ) = showsadd e1. s h o w S t r i n g " < ". showsadd e2 showscmp ( e1 : >: e2 ) = showsadd e1. s h o w S t r i n g " > ". showsadd e2 showscmp e = showsadd e showsadd : : Expr > ShowS showsadd ( e1 :+: e2 ) = showsadd e1. s h o w S t r i n g " + ". showsmul e2 showsadd ( e1 : : e2 ) = showsadd e1. s h o w S t r i n g " ". showsmul e2 showsadd e = showsmul e...
Esimerkki: Show Expr... showsmul : : Expr > ShowS showsmul ( e1 : : e2 ) = showsmul e1. s h o w S t r i n g " ". showspow e2 showsmul ( e1 : / : e2 ) = showsmul e1. s h o w S t r i n g " ". showspow e2 showsmul e = showspow e showspow : : Expr > ShowS showspow ( e1 : ^ : e2 ) = showsunary e1. s h o w S t r i n g " ^ ". showspow e2 showspow e = showsunary e showsunary : : Expr > ShowS showsunary ( Negate e ) = showchar. showsunary e showsunary e = s h o w s P r i m a r y e s h o w s P r i m a r y : : Expr > ShowS showsprimary (C ( NumValue v ) ) = shows v showsprimary (C ( BoolValue True ) ) = s h o w S t r i n g " (0 == 0) " showsprimary (C ( BoolValue F a l s e ) ) = showstring " (0 /= 0) " s h o w s P r i m a r y (V s ) = s h o w S t r i n g s s h o w s P r i m a r y e = showchar (. showsexpr e. showchar )
Varoituksen sana Pidä huoli, että Show ja Read ymmärtävät toisiaan! (Vaihtoehtoisesti älä määrittele Readia.)