Løsningsforslag Skriftlig eksamen 5. januar 2011 Version 3, 2011-01-28 Spørgsmål 1 Spørgsmål 1.1 b c d 1 2 b c d Spørgsmål 1.2 Det regulære udtryk kunne være: (b c d)((b c d)(b c d)) Spørgsmål 1.3 Her er en let reduceret version af den NF man får fra Mogensens opskrift, idet der benyttes den oplagte konstruktion for én-eller-flere gentagelsen +: < 2 3 1 < 5 6 7 4 < 8 9 10 Spørgsmål 1.4 < S1 S2 S3 S4 S6 S7 S5 1
Spørgsmål 2 Spørgsmål 2.1 ρ 11 : int Spørgsmål 2.2 ρ 11 + 10 : int ρ 10 : int - (4) - (2) ρ true : bool ρ 22 : int - (pair) ρ (true, 22) : bool int - (pair) ρ (11 + 10, (true, 22)) : int (bool int) ρ e : t u - (fst) ρ fst(e) : t ρ e : t u - (snd) ρ snd(e) : u Spørgsmål 2.3 Regel (1) er korrekt. Den siger at udtrykket e r skal have par-type t u, og let-kroppen e b skal typetjekkes i et environment hvor x har type t og y har type u. Dette typetjek skal give en type t b som så er typen for hele let-udtrykket. Regel (2) er forkert fordi e b kunne være false, der jo umuligt kan have type int. Regel (3) er forkert fordi den ikke kræver at e r har en par-type. Regel (4) er forkert af samme grund faktisk kræver ikke en gang at e r er type-korrekt. Regel (5) er forkert af to grunde: for det første er det urimelig at kræve at e b har samme type t som første komponent af e r for det andet tillader den at x og y optræder i e r hvilket er meget ejendommeligt det ville tillade udtryk som dette: let (x,y) = (x,y) in x end som det er svært at tillægge nogen værdi. 2
Spørgsmål 3 Spørgsmål 3.1 Ligesom der er et terminalsymbol (eller token) TEXT for tekster omgivet af skråstreger, antager jeg at der er et terminalsymbol LBEL for navne på spørgeskemadefinitioner og spørgsmål. Questionnaire ::= "questionnaire" LBEL "{" Questions "}" Questions ::= * empty * Question Questions Optional ::= * empty * "optional" BaseQuestion ::= Optional "freetext" LBEL TEXT "" Optional "number" LBEL TEXT "" Optional "singlechoice" LBEL TEXT Textlist "" Optional "multichoice" LBEL TEXT Textlist "" Texts ::= TEXT TEXT Texts Textlist ::= "[" Texts "]" Spørgsmål 3.2 og 3.3 Main: QUESTIONNIRE NME LBRCE Questions RBRCE { ($2, $4) } Questions: * empty * { [] } Question Questions { $1 :: $2 } Optional: * empty * { false } OPTIONL { true } Question: Optional FREETEXT NME TEXT SEMI { Freetext($1, $3, $4) } Optional NUMBER NME TEXT SEMI { Number($1, $3, $4) } Optional SINGLECHOICE NME TEXT Textlist SEMI { Singlechoice($1, $3, $4, $5) } Optional MULTICHOICE NME TEXT Textlist SEMI { Multichoice($1, $3, $4, $5) } Texts: TEXT { [$1] } TEXT Texts { $1 :: $2 } Textlist: LBRCK Texts RBRCK { $2 } 3
Spørgsmål 4 Spørgsmål 4.1 Lidt fremsyn viser at det er nyttigt at definere en hjælpefunktion mapndconcat f xs af type ( a - string) - a list - string som anvender funktion f på alle elementer af listen xs og konkatenerer de resulterende strenge. (Funktionerne String.concat og List.map findes i PLCSD appendix, for eksempel): let mapndconcat f xs = String.concat "" (List.map f xs) let makettributes attributes = mapndconcat (fun (a, v) - " " + a + "=" + enquote v) attributes Man kan selvfølgelig også definere makettributes direkte, rekursivt: let rec makettributes attributes = match attributes with [] - "" (a, v) :: rest - " " + a + "=" + enquote v + makettributes rest Spørgsmål 4.2 Her skal man selvfølgelig benytte sig af den netop definerede makettributes funktion: let tag0 tag attributes = "<" + tag + makettributes attributes + "" let tag1 tag attributes contents = "<" + tag + makettributes attributes + "" + contents + "<" + tag + "" Spørgsmål 4.3 let makefreetext label ask = ask + ": " + tag0 "input" [("type","text") ("name",label)] Spørgsmål 4.4 Her bruges hjælpefunktionen fra 4.1. For at få hver tabellinje pænt på sin egen tekstlinje tilføjes et linjeskift "\n" men der står udtrykkeligt i opgaven at dette skal man ikke bekymre sig om: let maketable lines = tag1 "table" [] (mapndconcat (fun line - tag1 "tr" [] (tag1 "td" [] line) + "\n") lines) Løsningen kunne nok være blevet en anelse klarere ved at indføre nye hjælpefunktioner tr og td: let tr contents = tag1 "tr" [] contents let td contents = tag1 "td" [] contents let maketable lines = tag1 "table" [] (mapndconcat (fun line - tr (td line) + "\n") lines) Spørgsmål 4.5 Også her bliver svaret klarere ved at definere en hjælpefunktion makesinglechoice1 som genererer HTMLkode svarende til en enkelt valgmulighed. let makesinglechoice1 label choice = tag1 "input" [("type", "radio") ("name", label) ("value", choice)] choice let makesinglechoice label ask choices = ask + ":\n" + maketable (List.map (makesinglechoice1 label) choices) 4
Bemærk at hjælpefunktionen makesinglechoice1 kaldes med kun ét argument label resultatet er en partielt anvendt funktion af type string - string som er den List.map anvendes på. lternativt kan man anvende en anonym funktion: let makesinglechoice label ask choices = ask + ":\n" + maketable (List.map (choice - tag1 "input" [("type", "radio") ("name", label) ("value", choice)]) choices) Eller man kan definere en rekursiv hjælpefunktion hvis man ikke kan huske at List.map findes eller hvordan den virker men det skulle man gerne kunne. Spørgsmål 4.6 let makequestion question = match question with Freetext(isOptional, label, ask) - makefreetext label ask Number(isOptional, label, ask) - makenumber label ask Singlechoice(isOptional, label, ask, choices) - makesinglechoice label ask choices Multichoice(isOptional, label, ask, choices) - makemultichoice label ask choices 5