Föreläsning 8 i programmeringsparadigm. Kommentarer kring schacklabben.

Relevanta dokument
Föreläsning 5 i programmeringsparadigm. Tips kring programmering i Haskell och kring labbarna.

Föreläsning 6 i programmeringsparadigm. Tips kring programmering i Haskell och kring labbarna.

Föreläsning 5 i programmeringsparadigm.

Kursanalys för Programmeringsparadigm 2D1361, läsperiod 1 och 2 läsåret 2005/2006

DD1361 Programmeringsparadigm. Carina Edlund

Funktionell programmering DD1361

Föreläsning 7 i programmeringsparadigm. Ytterligare Högre ordningens funktioner: filter, foldr foldl. Hutton 7.2, 7.3 och 7.4.

Kungliga Tekniska Högskolan Ämneskod 2D1370 Tentamensdag 2001-maj-31 Tentamen i Funktionell Programmering Skrivtid 4 h

Föreläsning 8. newtype Chess = Chess [(Square, Chessman)] -- data ist f newtype OK -- data istället för newtype krävs om >1 konstruerare.

Enjoy Vattenfallsmodellen i funktionella språk

Nada Tentamensdag 2004 okt 18 Tentamen Programmeringsparadigm Skrivtid 5 h

Tentamen. Datalogi I, grundkurs med Java 10p, 2D4112, Lördagen den 30 november 2002 kl , salar E33, E34

Kap9. Operatorn.. Hudak 9.4 sid 11. Fermats förmodan, eller Fermats stora sats säger att. xm + ym == zm har heltalslösningar om och endast om m == 2.

Föreläsning 4 (och 5?) i programmeringsparadigm.

Välkomna till DIT012 IPGO. Tyvärr en bug i Google Docs: Sidnummer stämmer inte alltid. Alla anteckningar börjar på sidan 1.

Enjoy Vattenfallsmodellen i funktionella språk

Tentamensdag 2002-aug-20 Tentamen i Funktionell Programmering Skrivtid 5 h

Introduktion till Haskell

Introduktion till programmering. Standardfunktioner. Vad används datorer till? Standardfunktioner. Föreläsning 2. Prelude. $ ghci...

Föreläsning 8. Paradigmöversikt, paradigmhistoria, paradigmgeografi. Se även föreläsning 1.

Föreläsning 4 i programmeringsparadigm.

TDDC74 Lab 04 Muterbara strukturer, omgivningar

Men först: Några funktioner ur preluden. Introduktion till programmering. Uppgiften. Variationer av uppgiften. Föreläsning 4

Sätt att skriva ut binärträd

Del : Funktionell programmering. I alla deluppgifterna, använd Haskell och skriv typen för de identifierare du definierar.

Föreläsning 4 (och 5?) i programmeringsparadigm.

Föreläsning 8. Hudak kapitel 13. 2D1370 Funktionell programmering v15 torsdag

LÖSNINGSFÖRSLAG Programmeringsteknik För Ing. - Java, 5p

Lambdas. (och fler design patterns) Objekt-orienterad programmering och design (DIT952) Niklas Broberg, 2017

Senast. Idag. Icke-strikt evaluering. Strikt evaluering. Testa latheten! Lat evaluering. Plus och minus med lat evaluering. Testa latheten!

TDDC74 Programmering: Abstraktion och modellering Tenta, kl 14 18, 11 juni 2014

Datalogi I, grundkurs med Java 10p, 2D4112, Fiktiv tentamen, svar och lösningar och extra kommentarer till vissa uppgifter 1a) Dividera förs

Universitetet i Linköping Institutionen för datavetenskap Anders Haraldsson 2

TENTAMEN I PROGRAMMERING. På tentamen ges graderade betyg:. 3:a 24 poäng, 4:a 36 poäng och 5:a 48 poäng

Dagens föreläsning Programmering i Lisp Fö 5

Kungl. Tekn. Högskolan Förel 1, bild 1 Föreläsning 1: Introduktion ffl Kursinnehåll ffl Javarepetition ffl Referenser ffl Nyckelordet static ffl Klass

Dagens föreläsning Programmering i Lisp Fö 7. Sammanfattning funktionell programmering Exempel på funktionella programspråk

Använda Python Laboration 1 GruDat, DD1344

I kapitel 15 gör Hudak för reaktiva animeringar detsamma som han i kapitel 13 gör för animeringar. Resultatet är en module Fal.

BEGREPP HITTILLS FÖRELÄSNING 2 SAMMANSATTA UTTRYCK - SCHEME DATORSPRÅK

Tentamen, Algoritmer och datastrukturer

Nada KTH 2004 jan 12 Tentamen Programmeringsparadigm 2D1350 Skrivtid 5 h 8-13

TDDC74 Programmering: Abstraktion och modellering Tentamen, lördag 27 augusti 2016, kl 8 12

TDDC30. Objektorienterad programmering i Java, datastrukturer och algoritmer. Föreläsning 4 Erik Nilsson, Institutionen för Datavetenskap, LiU

TDDC74 Programmering: Abstraktion och modellering Tentamen, lördag 29 augusti 2015, kl 8 12

TDDC74 Programmering: Abstraktion och modellering Datortenta , kl 14-18

Föreläsning 9 i programmeringsparadigm. Paradigmöversikt, paradigmhistoria, paradigmgeografi. Se även föreläsning 1.

Föreläsning 3. Programmering, C och programmeringsmiljö

Tentamen i TDP004 Objektorienterad Programmering Praktisk del

Verktyg och Utvecklingsmiljö. Jochim von Hacht

725G61 - Laboration 7 Implementation av ett API. Johan Falkenjack

Tentamen i TDP004 Objektorienterad Programmering Praktisk del

Skolan för Datavetenskap och kommunikation. Programmeringsteknik. Föreläsning 16

Objektorienterad programmering i Java, datastrukturer och algoritmer. Föreläsning 4 Jonas Lindgren, Institutionen för Datavetenskap, LiU

Objektorienterade programmeringsspråk. Objektorienterade språk. Den objekt-orienterade modellen. Jämför med icke-oo

Föreläsning 17 UTBLICK: FORTSÄTTNINGSKURSER I DATAVETENSKAP + ANDROID

TDDC74 Lab 02 Listor, sammansatta strukturer

Föreläsning 3. Programmering, C och programmeringsmiljö

Universe Engine Rapport

Imperativ programmering

Föreläsning 7 Innehåll. Rekursion. Rekursiv problemlösning. Rekursiv problemlösning Mönster för rekursiv algoritm. Rekursion. Rekursivt tänkande:

TDDC30. Objektorienterad programmering i Java, datastrukturer och algoritmer. Föreläsning 11 Jonas Lindgren, Institutionen för Datavetenskap, LiU

Föreläsning 10 Datalogi 1 DA2001. Utskrift på skärmen. Syntax. print( Hej ) Hur är det? Hej. print( Hej,end= ) print( Hur är det? ) HejHur är det?

Datavetenskapligt program, N1COS

TDDE10 m.fl. Objektorienterad programmering i Java Föreläsning 6 Erik Nilsson, Institutionen för Datavetenskap, LiU

Labb i Datorsystemteknik och programvaruteknik Programmering av kalkylator i Visual Basic

Programmering I Tobias Wrigstad fredag, 2009 augusti 28

Tentamen TEN1 HI

Introduktion till programmering D0009E. Föreläsning 1: Programmets väg

Våra enkla funktioner eller procedurer

TDDC30. Objektorienterad programmering i Java, datastrukturer och algoritmer. Föreläsning 3 Jonas Lindgren, Institutionen för Datavetenskap, LiU

Introduktionsmöte Innehåll

Python. Python är, som Scheme, ett interpreterat språk men det finns kompilatorer för Python.

Del : Funktionell programmering. I alla deluppgifterna, använd Haskell och skriv typen för de identifierare du definierar.

LÖSNINGSFÖRSLAG TENTAMEN PROGRAMMERING I ETT FUNKTIONELLT SPRÅK ML, 5P

Python. Python är, som Scheme, ett interpreterat språk men det finns kompilatorer för Python.

TDDC74 Programmering: Abstraktion och modellering Tentamen, onsdag 9 juni 2016, kl 14 18

Föreläsning 3: Abstrakta datastrukturer, kö, stack, lista

Chapter 4: Writing Classes/ Att skriva egna klasser.

Föreläsning 6: Introduktion av listor

Funktionell programmering. Haskell. Ge#ng started...

DUGGA: Objektorienterade applikationer. Läs detta! Uppgifterna är inte avsiktligt ordnade efter svårighetsgrad.

Vem är vem på kursen. Objektorienterad programvaruutveckling GU (DIT011) Kursbok Cay Horstmann: Big Java 3rd edition.

Det finns många flaggor till g++,

Föreläsning Datastrukturer (DAT036)

PROGRAMMERINGSTEKNIK TIN212

Nada KTH 2003 okt 23 Tentamen Programmeringsparadigm 2D1350 Skrivtid 5 h 8-13

ITK:P1 Föreläsning 1. Programmering. Programmeringsspråket Java. Stark typning Explicit typning Strukturerat Hög säkerhet

Inledande programmering med C# (1DV402) Introduktion till C#

Tentamen Programmering fortsättningskurs DIT950

Omkoppling av in- och utmatning. In- och utmatning i Unix. Kommando exempel, ls, pipe forts. Kommando exempel, ls, pipe

NetBeans 5.5. Avsikt. Projektfönster

Teoretisk del. Facit Tentamen TDDC (6)

Classes och Interfaces, Objects och References, Initialization

Tentamen i kurserna Beräkningsmodeller (TDA181/INN110) och Grundläggande Datalogi (TDA180)

Eclipse. Avsikt. Nu ska ett fönster liknande figuren till höger synas.

Programmering II (ID1019)

Välkommen till. Datastrukturer, algoritmer och programkonstruktion. eller DOA

TDDE10 m.fl. Objektorienterad programmering i Java Föreläsning 6 Erik Nilsson, Institutionen för Datavetenskap, LiU

Inlämningsuppgiften. Föreläsning 9 Innehåll. Träd. Datastrukturer i kursen

Transkript:

Föreläsning 8 i programmeringsparadigm. Kommentarer kring schacklabben. Om man vill kontrollera hur mycket man skrivit i sina Haskell-moduler man köra unix-kommandot wc (word count):..> wc.hs 100 486 3292 Chess.hs 88 474 3432 ChessGraphics.hs 115 688 4839 Chessman.hs 56 245 1850 PlayChess.hs 21 99 653 PolygonGraphics.hs 72 373 2082 Square.hs 9 50 302 Vector.hs 461 2415 16474 total Dvs min lösning har 461 rader, 2415 ord eller 16 474 tecken. Skulle vi kunna gjort på ett bättre sätt, skulle ett kortare program varit bättre? Min lösning är programmerad med moduler som innehåller ADT för modellen av schacket (Square, Chessman, Chess och Vector), funktioner för vyn av typen..>[graphic] (ChessGraphics.hs, PolygonGraphics.hs) huvudfunktionen main::io () (PlayChess.hs) Detta sätt att utforma program/skript i olika paradigm rekommenderas i många böcker, man skriver många moduler som ofta implemterar en ADT och försöker få gränsnitten (engelska interface) så enkla som möjlig för att modulerna skall vara maximalt oberoende och individuellt modifierbara och kunna skrivas av olika personer. Gränsnitten i Haskell programmeras ju i Haskell med exportlistorna, i Javaklasser med private och public. Ju större ett projekt är, desto viktigare är detta arbetsätt. Våra ADT i Haskell implementerar nya typer vars värden vi kan använda i andra moduler. Lite grann kan vi säga att vi skapar ett schack-språk för att kunna programmera schack-problem. En ADT motsvarar i stort sett vad som matematiker kallar en algebra. Även programmering med Java brukar karakteriseras som programmering med abstrakta datatyper, och en java-klass är ju visserligen en typ i Java men instanserna är oftast modifierabara objekt, ej värden. Det blir dock mer att skriva om man gör på detta sätt. Till exempel kunde vi nöjt oss med att låta ett schack vara i stället för en lista med par av typen [(Square, Chessman)] eller t o m [((Int, Int), Chessman)] om vi struntar att skriva ADT Square data Chess = Chess [(Square, Chessman)] -- ev newtype

Programmeringen av många funktioner i Chess skulle då vara enklare, speciellt för den oerfarne, eftersom vi direkt skulle kunns använda alla funktioner för listor och skulle slippa skriva konstruktorn Chess på en massa ställen för skapa ny värden, mönsterpassa eller "plocka ut listan ur typen". Vi skulle slippa sånt som mönster(chess ((sq,cm):sqcms))) lokala bindningar let Chess((sq,cm):sqcms)) = new Chess (Chess...) i högerleden hjälpfunktioner och många slarvfel, parantesfel mm. Vidare skulle också vi kunna skriva alltihop i en enda modul, låta Haskell typa alla funktioner i stället för att själv skriva funktionernas typer, använda lamda-uttryck och stunta i kommentarer och blanka rader. Vårt schackprogram skulledå antagligen kunna skrivas med mindre än 200 rader, kanske mindre än 100 rader. Om man försöker skriva större program med sådan teknik bör man nog vara mycket skärpt och jobba helt ensam med projektet (och slippa jobba med det efter några år då man jobbat med annat). En kompromiss-metod är att använda typsynonymer, t ex type Chess = [(Square, Chessman)] Ett lite svårare exempel. ZipWith. De flesta exempel vi hittills sett har enkelt kunna programmeras med rekursion på ett ganska mekaniskt sätt, med listomfattning eller med lämplig funktion från Preluden. Ibland är det lite svårare, det kan krävas lite mer sofistikerad rekursion till exempel. Se t ex Hutton 6.3, 6.4, 6.5. Låt oss programmera zipwith som parar ihop element från två listor med en funktion. T ex Typen blir zipwith () [1,3,2] [14, 22, 44] blir [15, 25, 46] zipwith :: (a->b->c) -> [a]->[b]->[c] Eftersom två listor, som båda kan konstueras mpå två sätt med : samt [], är inblandade förutom slutresultatlistan får vi 22 = 4 fall i mallen. Sedan vi fyllt i högerleden får vi zipwith _ [] [] = [] zipwith _ (a:as) [] = [] zipwith _ [] (b.bs) = [] zipwith z (a:as) (b:bs) = z a b : zipwith z as bs Efter lite eftertanke kan vi komma fram till Preludens lite kortare definition: zipwith :: (a->b->c) -> [a]->[b]->[c] zipwith z (a:as) (b:bs) = z a b : zipwith z as bs zipwith _ = [] Jag tror faktiskt att Hutton inte tänkt riktig klart vid programmering av zip i avsnitt 6.3 sid 69.

Läsanvisning för funktionell programmering. Hela Hutton-häftet inklusive utdraget ur A gentle Introduction to Haskell ingår i kursen. Det enda som jag inte tycker om i Huttons bok boken är mönster av typen n1. En del av exemplen, ofta i slutet av kapitlen, kan du läsa om du vill få illustrerat hur man tänker, men kan ju också hoppas över eller läsas kursivt, t ex avsnitt 5.5, avsnitt 7.6. Kapitel 12 om lat evaluering kommer jag strax att tala om på ett lite annat sätt än vad Hutton gör, och kommer jag inte att ställa svårare frågor om lat evaluering. Kapitlet kan läsas kursivt. Det jag gjort utöver vad som behandlas i Hutton-häftet är främst IO-programmering (se labhäftet och föreläsning 6) och mer ingående om typklasser (föreläsning 7). När vi senare i kursen studerar syntaxanalys, efter det av vi behandlat logikprogrammering, kommer vi att använda Haskell igen. På tentamen försöker jag ge en del uppgifter som liknar vad man gjort när man labbat. Lat evaluering. (Hutton kapitel 12, Fokker 3.2.5, 3.2.6 sid 48-51). Haskell och "moderna" funktionella språk har lat evaluering. Jag har några ex av Björn vonsydow: Datastrukturer i Haskell" (48 s). Mycket trevlig läsning som bland annat tar upp mer om hur Haskell fungerar, lat evluering och effektivitetssynpunkter. Har används på Chalmers i fortsättningskursen i programmering. I Haskell "körs" programmen genom att vi beräknar ( == ger värden till == evaluerar) uttryck. Uttryck kan skrivas som teckensträngar eller som träd (upp-och-nedvända, praxis i datalogi) : (14 4) (1 22) square (12) 14 4 1 22 $ square 1 2 $ == applikation Evalueringen kan skrivas om omskrivningar/omritningar (==förenklingar, == reduktioner) av deluttryck (ett redex, reducible expression) / delträd. Ibland finns det flera redex att välja på. Två olika strategier: använda "innersta" redex (redex som inte innehåller andra redex) / förenkla trädet från löven använda bästa "yttersta" redex (om möjligt redex inte i redex)/ förenkla trädet från roten. Ett exempel på nästa sida :

square (12) $ square 1 2 För komma vidare måste vi ha def på square (\n -> n n) (12) \n -> n n $ 1 2 Vi räknar ut argumentet (\n -> n n) 3 \n -> n n Applicerar $ 3 3 3 3 Multiplicerar 9 9 3 Innermost evaluation (Function call-by-name) Applicerar.. (12).. 1 2 Vi tvingas addera, strict.. 3.. Applicerar (12) (12) 1 2 1 2 Vi tvingas addera, strict (3) (12) 3 1 2 3 Multiplicerar Vi tvingas addera, strict (3) (3) 9 9 3 3 Multiplicerar 9 Lazy evaluation 9 Outermost evaluation, (Function call-by-name)

Innermost evaluation, som också kallas strikt evaluering eller eager evluation, är det vanligaste i imperativa språk och upplevs nog som det självklara sättet av de flesta. Emmellertid är icke-strirkt evaluering bättre om vissa redex/delträd aldrig behöver evalueras eller vid rekursion som kan ge oändlig rekursion. Outermost evaluation på ett naivt sätt (längst till höger på föregående sida), kan ge ineffektiva program pga att vissa uttyck beräknas flera gånger. Detta kan dock undvikas med lat evaluering; I datorns minne lagras inte uttrycken direkt utan med referenser (pekare) till uttrycken. Referenser till uttryck från på flera ställen refererar bara till ett enda ställe. Krävs förenkling av uttryck förenklas det då bara en enda gång. Uttrycksträdet blir istället en graf. Lat evaulering gör att program som ibland aldig skulle sluta köras, terminera, med innermost evaluation terminera. Med lat evaluering kan man programmera med rekursiva funktioner utan basfall och med potentiellt oändliga datastrukturer. Ett mycket fiffigt och snabbt sätt att lista Fibonacchi-talen: Talföjden (fibs), talföljdens svans (tail fibs) och svansen av talföljdens svans (tail tail fibs) hänger ihop så här: 1 1 2 3 5 8 13 21 fibs 1 2 3 5 8 13 21 34 tail fibs 2 3 5 8 13 21 34 55 tail tail fibs dvs vi kan definiera en konstant fibs som fibs :: [Integer] fibs = 1 : 1: zipwith () fibs (tail fibs) med Prelude-funktionen tail tail (_:xs) :: [a] -> [a] = xs Kör man fibs räknar hugs ut och skriver ut talen i listan i all oänlighet. Vill man ha de 100 första skriver man take 100 fibs Prelude-funktionen take : take :: Int -> [a] -> [a] take n _ n <= 0 = [] take _ [] = [] take n (x:xs) = x : take (n-1) xs Exempel på vad som händer (reservation för fel..)

take 5 fibs för att välja ekvation för take 5 måste vi veta mer om fibs, blir take 5. (:) 1 (:) 1 zipwith (). tail. vi kan välja ekvation för take 5, bindningar take 5. (:) binds till x 1 binds till xs (:) 1 zipwith (). tail. 1: take 4. (:) 1 använder högerledet, blir (:) 1 zipwith (). tail. dags för take 4, vi kan välja ekvation för take 4, bindningar 1: 1:take 3. (:) 1 (:) binds till x 1 binds till xs zipwith () tail.. använder högerledet, blir 1: 1:take 3. (:) 1 (:) 1 zipwith (). tail. 1:1: take 3. (:) 1 för att välja ekvation för take 3 måste vi veta mer om zipwith.., och måste då vet räkna ut tail.., blir (:) 1 zipwith ()..

använder högerledet för zipwith, blir 1:1:take 3. (:) 1 (:) 1 (:) (1 1) zipwith ().. nu kan vi välja ekvation för take 3, använd högerledet, x binds till 1 1 som räknas ut, xs binds till zipwith... 1:1:2:take 2. (:) 1 (:) 1 (:) 2 zipwith ().. för att välja ekvation för take 2 måste vi veta mer om zipwith.., blir... osv blir 1:1:2:3:5 : take 0 1:1:2:3:5 : []. grafen blir Talen som står längst till vänster i bilderna dvs 1, 1 1, 1 1 2 är nog också egentligen pekare in till motsvarande tal i grafen, men jag har skrivit ut dem för att det skall bli tydligare. Märk att användning av tail eller mönsterpassning på mönster av typ x:xs ej innebär att kopior skapas, bara omflyttning av pilar! Dvs minne förbrukas ej! Detta beror på att värden aldrig förändras, vi har ej destruktiv uppdatering i minnet i funktionella språk. Körning av fibs!! 5 skulle fungera på liknande sätt men slutresultatet skulle då bli en enda pekare in i grafen. En del av grafens noder skulle då ej refereras, dvs ej "pekas på", och kan tas bort, varvid ytterligare noder ej refereras, varför de kan tas bort, osv rekursivt. Det görs automatiskt i funktionella språk, liksom i Java, för att spara minne av en skräpsamlare, (engelska garbage collector).

The Awkard Squad: Haskell och kod i andra språk. Överkurs. Verkligheten Verkligheten c o n c u r r e n c y. Interaction ( -> IO a) föreläsning 6 Computational Kernel ("Vanlig Haskell") samverkan med kod skriven i andra språk e c r a r t o c r h Verkligheten Verkligheten För att Haskell skall slå igenom krävs också att de fyra "skalbitarna" i bilden ovan finns. I Haskell löses detta med IO a - programmering. Vill man kompilera Haskellprogram (slutresultatet skall då vara main :: IO(), som kan köras direkt fån operativsystmet) är den vanligaste kompilatorn ghc. Till den finns utvidgningar och bibliotek för de alla skalbitarna. Haskell har en standard (senare versioner av ghc och hugs följer den) för att kommunicera med kod skrivna i andra språk, "Foreign Function Interface 1.0 ". Den som är intressarad kan få mer information här: http://www.cse.unsw.edu.au/~chak/haskell/ffi/ Jag har gjort lite experiment med en tidigare version och fått kod i Haskell att samarbeta med kod i C. Jag har mestadels använt Haskell-kompilatorn ghc/5.04.2, som även kan kompilera c-kod Några axplock bland mina experiment finns på tre underkataloger till /info/progp03/haskellandc/. Kompilerings- och köranvisningar finns i.hs filerna. Kopiera filerna till egen katalog. Vid kompileringarna uppstår en massa nya filer, de körbara filerna blir stora. Lästips : Simon Peyton Jones :Tackling the awkward squad: monadic input/output, concurrency, exceptions, and foreign-language calls in Haskell (länk finns på kursens startsida). Bland de mer lättlästa artiklana om IO a. Handlar om det som brukar saknas i vanliga Haskell-böcker, och delar av Haskell som ofta är viktiga i "verkliga" projekt. För att komma åt artiklen måste man kunna gunzip.

Så här får man tillgång till ghc:..>module add ghc Man kan nu använda ghc interaktivt på detta sätt (mycket likt som man använder hugs, men man kan inte använda SOEGraphics):..>ghci Med ghci kan blanda ett interaktivt körsätt av någon Haskell-module med färdigkompilerad kod för importerade moduler. Vill man göra rena kompileringar skrivar man..>ghc...... Kompilatorn genererar C-kod, som därefter automatiskt kompileras med C-kompilatorn gcc och laddas med ld. Jag har lärt mig att även blanda in kod som skrivits med C, jag kanske skriver mer om detta i kommande föreläsningshäften. Haskell och Tcl/Tk. Överkurs. Tcl/Tk är, tror jag, C-världens sätt att göra GUI program på samma sätt som man i Java kan göra program med knappar (Buttons) och andra grafiska komponenter. I Bremen har man gjord ett paket HTk i Haskell som använder Tcl/Tk. Jag har lyckats kombinera detta med vår schackmodell från labbarna: Interaction main i PlayChessTcl.. changechess i PlayChessTcl modell Square Chess Chessman vy styrning Computational Kernel ("Vanlig Haskell") Shell -> IO a PlayChessTcl innehåller kod för hela vyn och den interaktiva delen av styrningen. Om du har lust att pröva min PlayChessTcl tillsammans med dina Sqaure, Chess och Chessman så finns programmet på /info/progp03/playchesstcl.hs. Man måste ha kompletterat Chess på det sätt som beskrivs i steg 8 och 9, namnen på vissa fuktioner måste ju stämma osv. Kompilering och laddning tar lång tid, den körbara koden blir 8 MByte, det har varit mycket krångel innan vi fick Htk att funka, så lycka till...

Däremot : Den rena Haskell-delen (modellen från SOEGraphics- versionen) var bara att smacka in, det funkade direkt (förståss!?). Hur man kompilerar och laddar står i början av filen Du kan (förhoppningsvis) även köra mitt program som...>setenv LD_LIBRARY_PATH ${LD_LIBRARY_PATH}:/pkg/gnu-libs/1.1/lib...>PlayChessTcl Avancerad kurs i funktionella språk. 2D1456, Advanced Functional Programming, 4 credits, D Why should I renounce for you, dear Haskell, My much yearned for side-effects? - Don Smith Course teacher: Course Description Johan Glimming In this course we study functional programming languages from two points of view: 1) their use as foundations for programming languages such as Java, 2) their use in their own right as one of the most powerful programming paradigms. We will study a range of topics, starting with the foundations of lambda calculus (both untyped, typed, and second-order), type inference and the Hindley-Milner type system, type classes, monads, data structures and algorithms in a (purely) functional setting, and finally program transformations, an excellent formal method for development of correct programs from their specifications. Students will have plenty of opportunity to explore advanced functional programming in their mini-projects, examined non-trivial programming exercises. The underlying theory of functional programming is explained in a series of 14 two-hour lectures. Rekomenderas varm! Haskell, paradigmer och multimedia. I denna roliga bok (som jag använde som kursbok i en 5p-kurs i funktionell programmering, kursbok för 2D1456, Advanced Functional Programming) : Paul Hudak: The Haskell School of Expression, Learning Functional programming through multimedia. ISBN 0-521-64408-9 används Haskell för att göra animeringar och datorspel i Haskell. Animeringarna ses som värden av typ Time -> [Graphic]. Animeringar och datorspel har ju mycket IO och mycket jämlöpande processer, vilket visar att paradigmgänserna är ganska konstlade. Boken innhåller också avsnitt om robotprogrammering och om musik.

Ett lite svårare exempel. Myntväxlingsproblemet. De flesta exempel vi hitills sett har enkelt kunna programmeras med rekursion på ett ganska mekaniskt sätt, med listomfattning eller med lämplig funktion från Preluden. Ytterligare ett exempel. Växla ett belopp till svenska mynt. Exempel på körning av det färdiga programmet : Main> change 2750 "2 tiokronor, en femkrona, 2 kronor och en femtioering" dela upp problemet : change :: Int -> String change = pretty. howmany. (change1 swedcoins) swedcoins :: [Int] swedcoins = [1000, 500, 100, 50] change1 presenterar resultatet på denna form: Main> change1 2750 ger detta resultat [1000, 1000, 500, 100, 100, 50] howmany. change1 presenterar resultatet på denna form: Main> (howmany.change1) 2750 ger detta resultat [(2,1000), (1,500), (2,100), (1, 50)] Delproblem: change1 : change1 :: [Int] -> Int -> [Int] change1 [] amount = [] change1 (c:cs) amount amount >= c = c : change1 (c:cs) (amount - c) otherwise = change1 cs amount

Delproblem: Snyggare resultat med howmany: För att förvandla [1000, 1000, 500, 100, 100, 50] till [(2, 1000), (1, 500), (2,100), (1, 50)] försöker skriver vi en funktion howmany :: [a] -> [(Int, a)] Parametern är en lista; typen lista har två konstuerare : []; vi startar med standardmallen howmany [] = howmany (x:xs) = Icke-rekusiva fallet är lätt, men det rekursiva fallet, vad sakll vi göra med x och rekursionsantagandet (howmany xs)? howmany [] = [] howmany (x:xs) =???? x (howmany xs) Lite svårare! Till exempel ska 100 slås ihop med [(1, 100), (1, 50)] eller 100 slås ihop med [(1, 50)]. Konventionell lösning : Funktionella programmerare definerar funktioner! Definiera en hjälpfunktion addon för????! addon x [] = [(1,x)] addon x ((i,y ) : iys) x == y = (1i, y): iys otherwise = (1, x) : (i,y ) :iys Klart? Nja vid provkörning får vi : ERROR "Money.hs":3 - Cannot justify constraints in explicitly typed binding Expression : howmany Type : [a] -> [(Int,a)] Given context : () Constraints : Eq a Typen är för generell; Vi får byta till howmany :: [a] -> [(Int, a)] howmany :: Eq a => [a] -> [(Int, a)] Klart! Trimmning : Tittar vi på definitionen på howmany ser vi om vi är vana att det är en "vikning", alltså är t ex detta en kortare definition: howmany = foldr addon [] n

En sämre lösning: Om vi vill slippa skriva en ny funktion för att programmera det rekursiva högerledet???? x (howmany xs) i den icke-akumulerande lösningen kan vi göra så här (lite imperativt; "först så gör vi rekusionsantagandet och mönsterpassar så vi får ut de delar vi behöver, och sedan är det lättare att skriva det vi vill ") howmany (x:xs) = let (i, y) : iys = howmany xs in if x == y then (1i, y): iys else (1, x) : (i,y ) :iys Hugs protesterar int men när vi provkör får vi fel (Den som inser felet är duktig)..> howmany [2, 2, 2, 3] Program error: {howmany_v1314 []} Problemet är att när vi har ett lista med ett elemnent ; howmany (2:[])passar (x:xs) med x bundet till 2 och med xs bundet till []. Sedan försöker vi göra let in (i, y) : iys = howmany xs dvs, eftersom howmany [] = [], (i, y) : iys = [] vilket inte går. En korrekt lösning måste ha ett basfall till, vilket är svårt att inse: howmany [] = [] howmany (x:[]) = [(1, x)] howmany (x:xs) = let (i, y) : iys = howmany xs in if x == y then (1i, y): iys else (1, x) : (i,y ) :iys En akumulerande lösning på howmany: howmany list = reverse (hm list [])-- reverse annars 50-oering först hm :: Eq a => [a] -> [(Int, a)] -> [(Int, a)] hm [] acc = acc hm (x:xs) [] = hm xs [(1, x)] hm (x:xs) ((i,y ) : iys) x == y = hm xs ((1i, y):iys) otherwise = hm xs ((1, x) : (i,y ) : iys)

Delproblem: Resultatet som sträng med pretty : För att förvandla [(2, 1000), (1, 500), (2,100), (1, 50)] till " 2 tiokronor, 1 femkrona, 2 kronor och en femtioöring " Hur gör vi då? Hur formaterarar vi strängar? Med standardfunktioner! Första försök : pretty :: [(Int, Int)] -> String pretty ims = concat [show i " " tocoin m ", " (i, m)<-ims] tocoin :: Int -> String tocoin 1000 = "tiokronor" tocoin 500 = "femkrona" tocoin 100 = "kronor" tocoin 50 = "femtioering" tocoin _ = "" Körning: pretty (howmany [1000, 1000, 500, 100, 100, 50]) ger "2 tiokronor, 1 femkrona, 2 kronor, 1 femtioering, " Ett andra försök : pretty :: [(Int, Int)] -> String pretty ims = concatspec [ fix (i, m) (i, m) <- fix :: (Int, Int) -> String fix (1, 1000) = " en tiokrona" fix (i, 1000) = show i " tiokronor" fix (1, 500) = " en femkrona" fix (i, 500) = show i " femkronor" fix (1, 100) = " en krona" fix (i, 100) = show i " kronor" fix (1, 50) = " en femtioering" fix (i, 50) = show i " femtioeringar" fix _ = "" concatspec :: [String] -> String concatspec [] = "." concatspec (x:[]) = x concatspec (x1:x2:[]) = x1 " och " x2 concatspec (x :xs) = x ", " concatspec xs ims] Körning:..> pretty (howmany [1000, 1000, 500, 100, 100, 50]) ger "2 tiokronor, en femkrona, 2 kronor och en femtioering",

Hela programmet: swedcoins :: [Int] swedcoins = [1000, 500, 100, 50] change1 :: [Int] -> Int -> [Int] change1 [] amount = [] change1 (c:cs) amount amount >= c = c : change1 (c:cs) (amount - c) otherwise = change1 cs amount howmany = foldr addon [] n -- ev akumulerande lösning istället where addon x [] = [(1,x)] addon x ((i,y ) : iys) x == y = (1i, y): iys otherwise = (1, x) : (i,y ) :iys pretty ims = concatspec [ fix (i, m) (i, m) <- fix :: (Int, Int) -> String fix (1, 1000) = " en tiokrona" fix (i, 1000) = show i " tiokronor" fix (1, 500) = " en femkrona" fix (i, 500) = show i " femkronor" fix (1, 100) = " en krona" fix (i, 100) = show i " kronor" fix (1, 50) = " en femtioering" fix (i, 50) = show i " femtioeringar" fix _ = "" concatspec :: [String] -> String concatspec [] = "." concatspec (x:[]) = x concatspec (x1:x2:[]) = x1 " och " x2 concatspec (x :xs) = x ", " concatspec xs change :: Int -> String change = pretty. howmany. (change1 swedcoins) ims] För att framhäva hur funktionerna använder varandra skulle man kunna ha lokala definitioner av hjälpfuktioner och få en struktur som change =... where swedcoins =... change1 =... howmany =... where addon =... pretty =... where concatspec =... fix =...