Kerätään seuraavaksi muutama kirjoitustestin tuloksista laadittu kuva pieneen ikkunaan, joka on tarkoitus myöhemmin liittää osaksi pääohjelmaa.
Vertailtavat suureet on koottuna listaan
framelist, joka sisältää tietueina viiden kuvan piirtämiseen tarvittavat selitteet ja funktiot:
framelist = [
("X = Järjestysluku\nY = Nopeus (mrk/min)",
Count, speedResult, earlierFst),
("X = Päivämäärä\nY = Nopeus (mrk/min)",
Calc dateResult, speedResult, earlierFst),
("X = Nopeus (mrk/min)\nY = Virheprosentti",
Calc speedResult, errorProsResult, slowerFst),
("X = Sijoitus\nY = Nopeus (mrk/min)",
Count, speedResult, fasterFst),
("X = Päivämäärä\nY = Virheprosentti",
Calc dateResult, errorProsResult, earlierFst)]
Koska tarvitsemme erilaisia kriteereitä tiedon lajittelemiseen, on varmaankin hyvä luopua ajatuksesta sisällyttää lajittelukriteeri Haskell-kielen tyyppiluokkiin. Laaditaan sen sijaan vertailufunktiot ja lajitellaan tulokset funktiolla
sortBy, joka saa vertailufunktion ensimmäisenä parametrinaan.
Lajittelukriteereinä ovat seuraavassa "nopeampi ensin", "hitaampi ensin", "aikaisempi ensin".
fasterFst (Result date1 mrks1 rnk1 errs1) (Result date2 mrks2 rnk2 errs2) =
if mrks1 /= mrks2
then mrks2 `compare` mrks1
else date1 `compare` date2
slowerFst (Result date1 mrks1 rnk1 errs1) (Result date2 mrks2 rnk2 errs2) =
mrks1 `compare` mrks2
earlierFst (Result date1 mrks1 rnk1 errs1) (Result date2 mrks2 rnk2 errs2) =
date1 `compare` date2
Nämä funktiot saavat parametreinaan kaksi tietotyypin
Result arvoa ja ne poimivat tarvittavat kentät tietotyypistä ja suorittavat vertailun. Tietotyypin
Result määrittely on pääohjelman mukainen, jolloin tulostiedot luetaan tyyppiluokan
Read avulla.
data Result = Result {
rDate :: String,
rMrks, rRank, rErrs :: Int
} deriving (Read, Show)
Vastaavasti virheprosentti ja nopeus saadaan funktioilla
errorProsResult ja
speedResult.
errorProsResult (Result date1 mrks1 rnk1 errs1) =
errorPros errs1 mrks1
speedResult (Result date1 mrks1 rnk1 errs1) =
speed mrks1
Järjestysluku ei sisälly tietotyyppiin
Result, joten se tuotetaan funktiolla
[1.0..].
Haskell-kieli on voimakkaasti tyypitetty kieli ja tästä johtuen myös listan alkioiden tulee olla samaa tyyppiä. Esimerkiksi lista
[5,2,"numerot","vs","merkkijonot"] ei ole sallittu. Ongelma ratkaistaan määrittelemällä tietotyyppi, joka kokoaa yhteen molemmat tapaukset.
data NumberOrString = Numb Int | Str String
list1 = [Numb 5, Numb 2, Str "numerot", Str "vs", Str "merkkijonot"]
Samoin listoissa esiintyvien funktioiden tulee olla samaa tyyppiä. Tämän mukaisesti varustetaan järjestysluvun tuottava funktio konstruktorilla
Count ja tietuetta
Result käyttävä funktio konstruktorilla
Calc, jolloin kuvalista saadaan esitettyä yhtenäisesti ja tarvittavat arvot laskettua funktiossa
collectResults. Y-akselilla konstruktoreita ei tarvita, sillä siellä kaikki funktiot ovat samaa tyyppiä.
type RFunction = Result -> Double
data FuncResult = Count | Calc RFunction
collectResults xFunc yFunc sortCrit values =
zip (xResult xFunc) yResult
where
xResult Count = [1.0..]
xResult (Calc f) = map f sortedByCrit
yResult = map yFunc sortedByCrit
sortedByCrit = sortBy sortCrit values
Funktio
zip kokoaa tuttuun tapaan kaksi listaa kaksialkioisten tietueiden muodostamaksi listaksi.
> zip [1..] "abcd"
[(1,'a'),(2,'b'),(3,'c'),(4,'d')]
Piirtämisen nopeuttamiseksi aikaisemmat ruksit on korvattu suorakulmioilla.
drawOneMarker cr (r,g,b) = do
rectangle (-cr) (-cr) cr cr
setSourceRGBA r g b 0.5
fill
Kuvat sijoitetaan pystysuuntaiseen laatikkoon
upbox funktiolla
createFrames. Tämä laatikko asetetaan vieritysikkunaan
scrolledWin ja vieritysikkuna edelleen pääikkunan ensisijaiseksi sisältökomponentiksi.
upbox <- vBoxNew False 0
createFrames valuess upbox
scrolledWin <- scrolledWindowNew Nothing Nothing
scrolledWindowAddWithViewport scrolledWin upbox
scrolledWindowSetPolicy scrolledWin PolicyAutomatic PolicyAutomatic
set window [
containerChild := scrolledWin,
windowDefaultWidth := 380,
windowDefaultHeight := 380 ]
Ohjelmakoodi:
http://personal.inet.fi/koti/jhii/ruksit-06.hs