Functioneel programmeren Practicumopgave 1: Een functionele querytaal Deze practicumopgave draait om het in Haskell inpassen van een eenvoudig querytaaltje voor databases. We zullen database-tabellen representeren met waarden van het volgende type: type Table = (String, [String ], [[String ]]). Een Table-waarde is dus een drie-tupel; de componenten van zo n tupel komen overeen met, achtereenvolgens, de naam van de tabel, de namen van de kolommen en de records in de tabel. Alle waarden in een record worden gerepresenteerd met behulp van String-waarden. Hieronder volgen twee voorbeelden van tabellen die op deze manier gerepresenteerd zijn. De eerste tabel bevat de hoogste tien noteringen in de Nederlandse Top 40 voor week 7 van 2008: top10 :: Table top10 = ("Top10", ["Nr", "Artist", "Title"], [ ["1", "Mark Ronson ft. Amy Winehouse", "Valerie"], ["2", "Alain Clark", "Father and Friend"], ["3", "Leona Lewis", "Bleeding Love"], ["4", "Kane", "Catwalk Criminal"], ["5", "Colbie Caillat", "Bubbly"], ["6", "Anouk", "I Don t Wanna Hurt"], ["7", "Timbaland ft One Republic", "Apologize"], ["8", "Lenny Kravitz", "I ll Be Waiting"], ["9", "DJ Jean", "The Lauch Relaunched"], ["10", "Rihanna", "Don t Stop the Music"] ] ). De tweede tabel bevat, voor sommigen van de artiesten uit de vorige tabel, informatie over de genres waarbinnen ze actief zijn: genre :: Table genre = ("Genre", ["Artist", "Genre"], [ ["Alain Clark", "Pop"], ["Anouk", "Pop"], ["Anouk", "Rock"], ["DJ Jean", "Dance"], ["Kane", "Rock"], ["Lenny Kravitz", "Rock"], ["Lenny Kravitz", "Soul"], ["Rihanna", "R&B"] ] ). 1
Opgave 1 printtable :: Table IO () die een tabel weergeeft op het scherm. printtable top10 Top10: Nr Artist Title ------------------------------------------------------- 1 Mark Ronson ft. Amy Winehouse Valerie 2 Alain Clark Father and Friend 3 Leona Lewis Bleeding Love 4 Kane Catwalk Criminal 5 Colbie Caillat Bubbly 6 Anouk I Don t Wanna Hurt 7 Timbaland ft One Republic Apologize 8 Lenny Kravitz I ll Be Waiting 9 DJ Jean The Lauch Relaunched 10 Rihanna Don t Stop the Music Zorg ervoor dat de uitvoer van je functie, voor wat betreft de layout, exact overeenkomt met het voorbeeld hierboven. Opgave 2 count :: Table Int die het aantal records in een gegeven tabel oplevert. print (count top10 ) moet bijvoorbeeld de uitvoer 10 opleveren. Opgave 3 project :: [String ] Table Table die een gespecificeerde deelverzameling van de kolommen uit een tabel selecteert. printtable (project ["Nr", "Title"] top10 ) 2
Top10: Nr Title ------------------------- 1 Valerie 2 Father and Friend 3 Bleeding Love 4 Catwalk Criminal 5 Bubbly 6 I Don t Wanna Hurt 7 Apologize 8 I ll Be Waiting 9 The Lauch Relaunched 10 Don t Stop the Music Opgave 4 select :: String (String Bool) Table Table zodat de expressie select k p t een tabel produceert met daarin alle records uit t waarvoor de waarde in kolom k aan het predicaat p voldoet. printtable (select "Nr" p top10 ) where p x = readint x 3 Top10: Nr Artist Title ---------------------------------------------------- 1 Mark Ronson ft. Amy Winehouse Valerie 2 Alain Clark Father and Friend 3 Leona Lewis Bleeding Love Opgave 5 De volgende te schrijven functie stelt ons in staat om twee tabellen te combineren. We mogen er hierbij vanuit gaan dat de te combineren tabellen precies één kolom gemeenschappelijk hebben. De tabellen top10 en genre, bijvoorbeeld, hebben deze eigenschap: ze bevatten beide een kolom "Artist". De gecombineerde tabel zal alle kolommen van de eerste tabel bevatten, gevolgd door alle kolommen van de tweede tabel die in de eerste tabel niet voorkomen. Het aantal kolommen in de gecombineerde tabel zal dus één kleiner zijn dan de som van de aantallen kolommen van de eerste en de tweede tabel. De records van de nieuwe tabel worden gevormd door records van de samenstellende tabellen te combineren waar deze dezelfde waarde in de gemeenschappelijke kolom hebben. De naam van de gecombineerde tabel wordt gevormd door de namen van de samenstellende tabellen samen te voegen. Schrijf nu een functie 3
join :: Table Table Table zodat join t 1 t 2 de tabellen t 1 en t 2 op de hierboven beschreven manier combineert. printtable (join top10 genre) Top10 Genre: Nr Artist Title Genre ------------------------------------------------------------- 2 Alain Clark Father and Friend Pop 4 Kane Catwalk Criminal Rock 6 Anouk I Don t Wanna Hurt Pop 6 Anouk I Don t Wanna Hurt Rock 8 Lenny Kravitz I ll Be Waiting Rock 8 Lenny Kravitz I ll Be Waiting Soul 9 DJ Jean The Lauch Relaunched Dance 10 Rihanna Don t Stop the Music R&B Aanwijzingen Bedien je van een nette programmeerstijl: zorg dat er niet te veel code op een regel terechtkomt (een goede richtlijn is maximaal 80 kolommen per regel) en voorzie je functies van duidelijk commentaar. Het gebruik van lijstcomprehensies en hogere-ordefuncties als map, foldr, filter en zip verdient aanbeveling. Deel je uitwerkingen op in kleine functies en test deze zo veel mogelijk in isolement. Om je complete implementatie van de functionele querytaal uiteindelijk grondig te testen kun je queries naar hartelust combineren. Zo zou de expressie printtable (project ["Nr", "Genre"] (select "Nr" p (join top10 genre))) where p x = readint x 6 de volgende uitvoer moeten opleveren: Top10 Genre: Nr Genre ---------- 2 Pop 4 Rock 6 Pop 6 Rock Inleveren Rangschik alle geschreven functies (dus zowel de gevraagde functies als de hulpfuncties) in een module Fql (voor functional query language ) en plaats deze module in een bestand Fql.hs. 4
Begin het bestand met commentaarregels waarin je naam, login en studentnummer vermeld worden. Als je de opdracht met zijn tweeën gemaakt hebt, vermeld dan de gegevens van beide teamleden. Lever dit bestand, met behulp van Submit, vóór maandag 3 maart 2008, 23:59 uur in via http://www.cs.uu.nl/docs/submit/ Zorg ervoor dat je code correct functioneert met Helium (versie 1.6). Als je module niet door de vertaler geaccepteerd wordt, komt je uitwerking niet in aanmerking voor een cijfer. Het overnemen van uitwerkingen, bijvoorbeeld van medestudenten of van het internet, is niet toegestaan. 5