Tyyppejä ja vähän muutakin TIEA341 Funktio ohjelmointi 1 Syksy 2005
Viime luennolla... Haskellin alkeita pääasiassa Hello World!... ja muita tutunoloisia ohjelmia Haskellilla Haskellin voima on kuitenkin aivan jossain muualla!... se voima, jota yritin viime luennon alussa esitellä yleisellä tasolla
Tänään Haskellin perustietotyypit Funktion määrittelystä Tyyppiluokat (käyttö)
Perustyypit: Integer kokonaislukujen tyyppi ei ylä eikä alarajaa vain muistin määrä rajoittaa lukujen suuruutta laskenta hidastuu lukujen suuruuden kasvaessa harjoituskäytössä paras kokonaislukuvaihtoehto tarpeellinen myös monissa sovelluksissa
Perustyypit: Int Vastaa suunnilleen Javan int tyyppiä Lukualue vähintää n 2 29...2 29 1 eli vähintään 30 bittiä GHC:ssä 32 bittiä (lukualue 2 31...2 31 1) suhteellisen nopea, nopeus luvun suuruudesta riippumaton kun lukualue riittää ja nopeudella on merkitystä maxbound, minbound
Perustyypit: Float ja Double Tutut liukulukutyypit Float on vähintään IEEE single precision Double on vähintään IEEE double precision
Lukuvakiot Kokonaislukuvakio 42 Liukulukuvakiot 42.0, 1.5e 15 kuormitettuja liukulukuvakio on Float tai Double sen mukaan, mitä käyttöyhteydessä tarvitaan kokonaislukuvakio on mitä tahansa lukutyyppiä sen mukaan, mitä käyttöyhteydessä tarvitaan jos tilanteeseen käy useampi tyyppi, valitaan Integer, jos se sopii, ja muuten Double
Aritmetiikka n: vastaluku, toimii kaikilla lukutyypeillä n + m: yhteenlasku, toimii kaikilla lukutyypeillä n m: vähennyslasku, toimii kaikilla lukutyypeillä n * m: kertolasku, toimii kaikilla lukutyypeillä n / m: liukulukujen jakolasku kokonaislukujen jakolasku ja jakojäännös n `div` m (pyöristää alaspäin), n `mod` m n `quot` m (pyöristää nollaa kohti), n `rem` m operandien tulee olla keskenään samaa tyyppiä!
Perustyypit: Boolean vakiot True ja False loogiset operaattorit: p && q: looginen JA p q: looginen TAI not p: looginen EI
Vertailu Yhtäsuuruusoperaattori: a == b Erisuuruusoperaattori: a /= b Suuruusvertailut: a < b, a <= b, a >= b, a > b compare a b palauttaa LT, jos a < b GT, jos a > b EQ, jos a == b LT, GT ja EQ ovat tyyppiä Ordering
Vertailusta vielä Kaikilla edellämainituilla tyypeillä toimii kaikki vertailuoperaattorit Mutta on olemassa tyyppejä, joita ei voi vertailla tällöin GHC saattaa sanoa No instance for Eq, kun yritetään käyttää ==:ää tai /=:ää No instance for Ord, kun yritetään käyttää operaattoreita <, <=, >= tai > taikka funktiota compare
Perustyypit: Char merkkien tyyppi (vertaa Javan char tyyppiin) periaatteessa kattaa koko Unicoden käytännössä Unicode tuki puutteellinen suomea toki pystyy käyttämään merkkivakiot pitkälti samanlaisia kuin Javassa: 'E' '\n' '\32' == '\o40' == '\x20' == ' ' Char ei ole lukutyyppi!
Vielä Charista fromenum muuttaa merkin Unicode koodikseen fromenum ' ' == 32 toenum muuttaa Unicode koodin merkiksi toenum 32 == ' ' toenum on kuormitettu, kohdetyypin (tässä Char) pitää selvitä yhteydestä!
Listat 1 [t] tarkoittaa t tyyppisten arvojen listaa Lista luodaan luettelemalla sen alkiot: [2,4,6,8] Tyhjä lista on [] merkkien lista [Char] on sama asia kuin merkkijonot, String Hei! tarkoittaa ['H','e','i','!']
Listat 2 Listat toteutetaan yleensä yhteen suuntaan linkitetttynnä listana kerran luotua listaa ei voi muuttaa! automaattinen muistinsiivous listan alkuun lisääminen on helppoa: 1 : [2,3,4] kaksoispiste on alkuunlisäämisoperaattori, ns. cons oikeanpuoleista operandia ei jouduta kopioimaan
Hahmonsovitus (listojen tapaus) Listaa voidaan myös purkaa case rakenteella: ekaalkio lista = case lista of [] > error Lista on tyhjä x : _ > x listaa sovitetaan seuraavien rivien hahmoihin jos tyhjä, tuloksena on virheilmoitus jos epätyhjä, listan eka alkio on rivin loppuosan ajan nimeltään x, loppuosa jätetään huomiotta (_) ekaalkio löytyy vakiokirjastosta nimellä head
Summa summa lista = case lista of [] > 0 x : xs > x + summa xs jälkimmäisessä funktio määritellään paloittain tai summa [] = 0 summa (x:xs) = x + summa xs vakiokirjaston funktio sum
Listan pituus pituus lista = case lista of [] > 0 _ : xs > 1 + pituus xs tai pituus [] = 0 pituus (_:xs) > 1 + pituus xs vakiokirjaston funktio length
ekaalkio ::??? ekaalkio [] = undefined ekaalkio (x : _) = x Mikä mahtaa olla ekaalkion tyyppi? vaikkapa [Integer] > Integer? mutta myös String > Char? Havainto: Integerin paikalle käy mikä vain tyyppi ekaalkio :: [a] > a a on tyyppimuuttuja, voidaan korvata millä tyypillä vain
summa ::??? summa [] = 0 summa (x:xs) = x + summa xs [Int] > Int? Kyllä. [Integer] > Integer? Kyllä. [Float] > Float? Kyllä. [Double] > Double? Kyllä. [a] > a? Ei! a:n voisi korvata vaikka Stringillä
summa ::??? summa [] = 0 summa (x:xs) = x + summa xs [a] > a? Ei! a:n voisi korvata vaikka Stringillä pitää voida sanoa, että b:n tulee olla lukutyyppi summa :: Num a => [a] > a a voidaan korvata millä tahansa lukutyypillä
Tyyppiluokat tyyppiluokka on joukko tyyppejä näitä tyyppejä yhdistää se, että niillä on yhteisiä operaatioita Eq on tyyppiluokka, johon kuuluvat kaikki tyypit, joilla on (==) ja (/=) Ord on tyyppiluokka, johon kuuluvat kaikki tyypit, joilla on (<) jne Num on tyyppiluokka, johon kuuluvat kaikki lukutyypit (niillä on mm. (+), ( ) ja (*))
Tyypin konteksti Num a => a > a Num a on konteksti a voi olla mikä tyyppi vain kunhan se kuuluu Numtyyppiluokkaan (Num a, Eq b) => b > b > a huomaa sulut ja pilkku a voi olla mikä tyyppi vain kunhan se kuuluu Num:iin b voi olla mikä tyyppi vain kunhan se kuuluu Eq:iin
Lukuvakioista vielä Kokonaislukuvakioiden tyyppi on Num a => a lue: mikä tahansa lukutyyppi Liukulukuvakioiden tyyppi on Fractional a => a lue: mikä tahansa murtolukutyyppi
Perustietotyypit: Monikot Monikot: parit, kolmikot, nelikot,... n:köt (Int, String) on parityyppi (42, Hei ) on pari () on myös monikko: 0:kko eli nollikko esiintyy esim. tyypissä IO () samoin käskyssä return () fst :: (a, b) > a snd :: (a, b) > b
Perustietotyypit: Maybe a parametrisoitu tyyppi (kuten listat) Maybe String Maybe Integer... Kahdenlaisia arvoja Nothing :: Maybe a Just :: a > Maybe a hyödyllinen esim. ilmaisemaan poikkeuksia
module Main where safediv :: Integral a => a > a > Maybe a safediv x y y == 0 = Nothing otherwise = Just (x `div` y) main = do putstrln Anna luku ns < getline putstrln Anna toinen luku (ei 0) ms < getline let n = read ns m = read ms case n `safediv` m of Just r > putstrln ( Jakolaskun tulos: ++ show r) Nothing > putstrln Nollalla jako!
Perustyypit: Either Kaksi parametria: Either a b Either String Int Either Int Char Kahdenlaisia arvoja Left :: a > Either a b Right :: b > Either a b
module Main where safediv :: Integral a => a > a > Either String a safediv x y y == 0 = Left division by zero otherwise = Right (x `div` y) main = do putstrln Anna luku ns < getline putstrln Anna toinen luku (ei 0) ms < getline let n = read ns m = read ms case n `safediv` m of Right r > putstrln ( Quotient: ++ show r) Left s > putstrln s
Listojen yhdistäminen Annettuna kaksi listaa, joista pitäisi muodostaa yksi lista jossa ekan listan alkiot ovat ekana ja toisen listan alkiot tulevat perässä Rekursiivinen ongelmanratkaisu: ratkaise perustapaus (tyhjä lista) ratkaise yleinen tapaus käyttäen hyväksi ratkaisua pienemmällä syötteellä yhdista [] ys = ys yhdista (x:xs) ys = x : yhdista xs ys