Föreläsning 3 i Programmeringsparadigm Repetition : Att definiera en funktion i Haskell. Labhäftet p 11. Layoutregler Hutton 2.4.3 p 26. Skåpregler för where and let. Vad vi hitills behanlat i Hutton, se slutet på föreläsningshäfte 2. Att gör egna datatyper. Se utdraget ur "AGentle Introduktion.." Appendix (bihang) till Hutton. Moduler, Abstrakta Data Typer (ADT). Exempel: ADT Complex( annan lösning än nedan) och ADT Date finns på /info/progp02/haskelllectures/f3. Där finns även en del andra program. Signaturbild och moduler för ADT Complex Float imagpart phase realpart mkcart magnitude mkpolar add sub mul Bool == /= neg Complex show String Pil Fet stil Cirkel funktion exporteras symboliserar alla värden i en datatyp
module Complex ( -- 4 a - Complex, mkcart, -- :: Float -> Float -> Complex ex (mkcomplex 1.0 1.0) är 1+i mkpolar, -- :: Float -> Float -> Complex ex (mkpolar 1.0 0.0) är 1+0i realpart, -- :: Complex -> Float ex realpar(mkcomplex 1.0 2.0) är 1.0 imagpart, -- :: Complex -> Float ex imagpart(mkcomplex 1.0 2.0) är 2.0 magnitude, -- :: Complex -> Float ex magnitud(mkcomplex 1.0 1.0) är 1.41... phase, -- :: Complex -> Float ex phase(mkcomplex 1.0 1.0) är 3.14../4.0 conjugate -- :: Complex -> Complex ex conjugate(mkcomplex 1.0 1.0) är 1-i add, -- Complex -> Complex -> Complex additon sub, -- Complex -> Complex -> Complex subtraktion mul, -- Complex -> Complex -> Complex multiplikatuontraktion neg, -- Complex -> Complex negering absval -- Complex -> Double absolutbelopp ) where -- funktionernas typer som ovan data Complex = C Float Float deriving (Eq,Show, Read) mkcart = C mkpolar m p = C ( m* cos p) (m * sin p) realpart (C x _) = x imagpart (C _ y) = y magnitude (C x y) = sqrt(x*x + y*y) phase (C 0 0) = 0 phase (C x y) = atan2 y x conjugate (C x y) = C x (-y) add (C a1 b1) (C a2 b2) = C (a1 + a2) (b1 + b2) sub (C a1 b1) (C a2 b2) = C (a1 - a2) (b1 - b2) mul (C a1 b1) (C a2 b2) = C (a1*a2- b1*b2) (a1*b2 +b1* a2) absval z = mkcart (magnitude z) 0.0 instance Num Complex where -- kan vi inte än (+) = add (-) = sub (*) = mul negate = neg abs = absval frominteger i = error "frominteger" signum z = error "signum in Complex" frominteger n = error " frominteger in Complex" På /info/progp02/haskelllectures/f3/complex.hs finns en annan lösning. Något om typklasser och "overloading" (Hutton 3.9, Fokker p 17, C&K p 5, 76). Något om ADT och moduler (C&K p 11, Chapter 10, "A Gentle Introduction i Labhäftet p 17.)
Listprogrammering i funktionella språk. Polymorfism. Tupler. Listor: Om vi gjorde det själva: Inbyggt i Preluden. OBS Speciell syntax! data List a = Nil data [a ] = [] Cons a (List a) a : [a] Listor har alltså konstruerararna [] :. Konstruerarna kan används i mönster. Speciella syntax för bekvämlighets skull:[1,2] == 1:2:[] Vad utmärker rekursiva datatyper? Del av värden i typen av samma typ. Kan vara "godtyckligt stora". Godtyckigt många element, alla av samma typ. Men allt tillåtet, t ex lisor med listor med... Strängar : Listor med Characters dvs i Preluden String = [Char]. Speciella syntax för bekvämlighets skull: "hej" == [ h, e, j ] == h : ( e :( j :[]])) :: [Char] Allt man kan göra, alla funktioner för listor användbara för strängar. Tupler: Inbyggt i Preluden. OBS Speciell syntax! Tupler, t ex par : data (a, b) = (a,b). Konstruerare (, ). Konstruerarna kan används i mönster. Fixt antal komponenter, som kan vara av olika typ. T ex ([[Char]], Int, ( [(Int,Bool)],String) Exempel: sum (Hutton 1.5 p 17Fokker p 13), prod (hutton 6.2 p 67C&K p 26 ), length (Hutton 6.2 p67, Fokker p 13, C&K p 74 ), När man skriver typer i typuttryck används stor initialbokstav för typer. Namn med små bokstäver i typuttryck betyder "vilken typ som helst". T ex length:: [a] -> Int.Detta kallas i Haskell polymorfism (Hutton 3.7, Fokker p 16, C&Kp 28 p 74). Dock : Om man till exempel skriver Num a => [a] -> a betyder a alla typer som är medlemmar i Num-gruppen, eller med Haskellterminologi : alla typer som är instanser i typklassen Num. Vi har inte sagt så mycket om typklasser än, hur de definieras och används kommer senare. Typklasser möjliggör overloading, som nämts tidigare. (++) (Hutton 6.2 p68, Fokker p 39, C&K p 28 ), zip (hutton 6.3 p 69.Fokker p 56 ) I Hutton har vi nu gjort det mesta överhoppade i kap 3 och 4, dock ek 4.5 och 4.6. Dessutom i Hutton har vi behandlat kapitele 6 utom lite svårare rekursion i 6.4 och 6.5. I Fokker bör nu de mesta i kapitel 1 kunna läsas och förstås, märk dock att en del praktiska saker gäller Gopher och inte Hugs som vi använder. Det vi inte behandlat än är 1.3.6 Functions on functions. C&K bör nu de mesta i kapitel 1, 3, 4, 8 kunna läsas och förstås
Ett exempel : "Korrekta" (Gratis blinummer, numera kan man mot betalning ha andra skyltar) bilnummer. Programmet, som visar att man ibland använder smarta mönster för att skriva eleganta program, finns på /info/progp02/haskelllectures/f4. module Bilnummer where ischarinrange :: Char -> (Char, Char) -> Bool ischarinrange c (cfrom, cto) = cfrom <= c && c <= cto {- eller? ischarinrange :: Char -> Char - > Char -> Bool ischarinrange c cfrom cto = cfrom <= c && c <= ct -- anropas som ischarinrange c A Z -} isuppercase :: Char -> Bool isuppercase c = ischarinrange c ( A, Z ) notusedletters :: String -- det samma som [Char] notusedletters = "IQV" -- == [ I, Q, U ] == I :( Q :( U : [] )) islegalletter :: Char -> Bool islegalletter c = isuppercase c && (not (elem c notusedletters)) -- Snyggare? c elem notusedletters islegal :: String -> Bool islegal (b1:b2:b3: :s1:s2:s3:[]) --"avancerat mönster " = ischarinrange b1 ( A, T ) && isdigit s2 && isdigit s1 && isdigit s3 && islegalletter b1 && islegalletter b2 && islegalletter b3 islegal _ = False -- isdigit :: Char -> Bool i Prelude -- elem :: Eq a => a -> [a] -> Bool i Prelude {- En tänkbar definition av elem är elemlk :: Eq a => a -> [a] -> Bool elemlk x (y:ys) = (x == y) (x elemlk ys) elemlk x [] = False -}
Hur hittar man "fördefinierade namn (funktioner)"? ( dvs exporterade namn från Prelude) Det är förstås jobbigt att komma ihåg alla fuktioner som finns i Prelude, det kan var lika bekvämt att skriva dem själv (oftast en, två eller tre rader). I slutet på Hutton finns en lista över några funktioner. Man kan titta på och söka med Search i preluden ( skriven i Haskell till största delen) med emacs, filnamn kopieras lämpligen, finns i ingressen när du startar hugs.)..> emacs /pkg/hugs98/dec01/os/share/hugs/lib/prelude.hs & Nedan finns är början på filen Prelude.hs. De vikigaste namnen i mitt tycke har jag skrivit med fet stil. De flesta av dessa kommer att introduceras under kursens gång. Längre ned i filen finns namnens definitionerna, i regel i Haskell, som man ofta kan förstå om man inte direkt av namnet (och typen, gör :i <namnet> i hugs ) förstår vad namnet står för. module Prelude ( -- module PreludeList, -- Listfunktioner map, (++), concat, filter, head, last, tail, init, null, length, (!!), foldl, foldl1, scanl, scanl1, foldr, foldr1, scanr, scanr1, iterate, repeat, replicate, cycle, take, drop, splitat, takewhile, dropwhile, span, break, lines, words, unlines, unwords, reverse, and, or, any, all, elem, notelem, lookup, sum, product, maximum, minimum, concatmap, zip, zip3, zipwith, zipwith3, unzip, unzip3, ReadS, ShowS, Read(readsPrec, readlist), Show(show, showsprec, showlist), reads, shows, read, lex, showchar, showstring, readparen, showparen, -- module PreludeIO, -- IO MM FilePath, IOError, ioerror, usererror, catch, putchar, putstr, putstrln, print, getchar, getline, getcontents, interact, readfile, writefile, appendfile, readio, readln, -- module Ix, Ix(range, index, inrange, rangesize), -- module Char, isascii, iscontrol, isprint, isspace, isupper, islower, isalpha, isdigit, isoctdigit, ishexdigit, isalphanum, digittoint, inttodigit, toupper, tolower,ord, chr, readlitchar, showlitchar, lexlitchar, -- module Numeric showsigned, showint, readsigned, readint, readdec, readoct, readhex, readsigned, readfloat, lexdigits, -- module Ratio, Ratio, Rational, (%), numerator, denominator, approxrational, -- Non-standard exports IO(..), IOResult(..), primexitwith, Addr, Word, StablePtr, ForeignObj,basicIORun, blockio, IOFinished(..), threadtoioresult, HugsException, catchhugsexception, primthrowexception, Bool(False, True), Maybe(Nothing, Just), -- Standardtyper Either(Left, Right), Ordering(LT, EQ, GT),
Char, String, Int, Integer, Float, Double, IO, -- List type: []((:), []) -- Tuple types: (,), (,,), etc. -- Trivial type: () -- Functions: (->) Rec, EmptyRec, EmptyRow, -- non-standard, should only be exported if TREX Eq((==), (/=)), -- Relationsoperatorer Ord(compare, (<), (<=), (>=), (>), max, min), Enum(succ, pred, toenum, fromenum, enumfrom, enumfromthen, enumfromto, enumfromthento), Bounded(minBound, maxbound), -- Numeriska operatorer -- Num((+), (-), (*), negate, abs, signum, frominteger), Num((+), (-), (*), negate, abs, signum, frominteger, fromint), Real(toRational), -- Integral(quot, rem, div, mod, quotrem, divmod, tointeger), Integral(quot, rem, div, mod, quotrem, divmod, even, odd, tointeger, toint), -- Fractional((/), recip, fromrational), -- Flyttal, matte funk. Fractional((/), recip, fromrational, fromdouble), Floating(pi, exp, log, sqrt, (**), logbase, sin, cos, tan, asin, acos, atan, sinh, cosh, tanh, asinh, acosh, atanh), RealFrac(properFraction, truncate, round, ceiling, floor), RealFloat(floatRadix, floatdigits, floatrange, decodefloat, encodefloat, exponent, significand, scalefloat, isnan, isinfinite, isdenormalized, isieee, isnegativezero, atan2), Monad((>>=), (>>), return, fail), Functor(fmap), mapm, mapm_, sequence, sequence_, (=<<), maybe, either, (&&), ( ), not, otherwise, -- Boolska operatorer subtract, even, odd, gcd, lcm, (^), (^^), fromintegral, realtofrac, -- Diverse fst, snd, curry, uncurry, id, const, (.), flip, ($), until, astypeof, error, undefined, seq, ($!) ) where -- Standard value bindings {Prelude} --------------------------------- infixr 9. infixl 9!! infixr 8 ^, ^^, ** infixl 7 *, /, quot, rem, div, mod, :%, % infixl 6 +, - --infixr 5 : -- this fixity declaration is hard-wired into Hugs infixr 5 ++ infix 4 ==, /=, <, <=, >=, >, elem, notelem infixr 3 && infixr 2 infixl 1 >>, >>= infixr 1 =<< infixr 0 $, $!, seq
Ett Exempel till :Signaturbild och moduler ADT Date Bool yearjan0tojulian leapyear Int Julian Year DayOfMonth January Febrary March April Month Dat date juliantodate datetojulian daynumberthisyear (-#) (+#) (-##) (+##) show date1 Date May June July August September October November December String show next dayofweek Monday Thuesday Wedensday show Day Thursday Friday Saturday Sunday
----------------------------------------------------------------------------------------------------------------------------- module Date where -- på /info/progp02/haskelllectures/f3/date.hs data Date = Dat Int Month Int deriving ( Show, Eq, Ord) data Month = January February March April May June July August September October November December deriving ( Show, Eq, Ord, Enum) data Day = Monday Thuesday Wedensday Thursday Friday Saturday Sunday deriving ( Show, Eq, Ord, Enum) type Julian = Int type Year = Int type DayOfMonth = Int date :: Year {- Int -} -> Month -> DayOfMonth -> Date date = Dat date1 :: Year -> Int -> DayOfMonth -> Date date1 y mi d = Dat y (toenum (mi - 1)) d leapyear :: Year -> Bool leapyear y = (y mod 4 == 0) && (not(y mod 100 == 0 )) (y mod 400 == 0) daynumberthisyear:: Date -> Int daynumberthisyear (Dat y m d) = daynumberthisyearx (Dat y m d) (Dat y January 1) 1 where daynumberthisyearx:: Date -> Date -> Int -> Int daynumberthisyearx d1 d2 i d1 == d2 = i otherwise = daynumberthisyearx d1 (next d2) (i+1) yearjan0tojulian:: Year -> Julian yearjan0tojulian y = -320 + (y-1858)*365 + (y-1857) div 4 - (y-1801) div 100 + (y-1601) div 400 datetojulian :: Date -> Julian datetojulian (Dat y m d) = yearjan0tojulian y + daynumberthisyear (Dat y m d) juliantodate :: Julian -> Date juliantodate i = juliantodatex i (Dat 1858 November 17) where juliantodatex:: Julian -> Date ->Date juliantodatex i (Dat y m d) datetojulian (Dat y m d) == i = Dat y m d datetojulian (Dat (y+1) January 1)<i = juliantodatex i (Dat (y+1) January 1) otherwise = juliantodatex i (next (Dat y m d)) next :: Date -> Date next (Dat y January 31) = Dat y February 1 next (Dat y February 28) leapyear y = Dat y February 29 otherwise = Dat y March 1 next (Dat y February 29) = Dat y March 1 next (Dat y March 31) = Dat y April 1 next (Dat y April 30) = Dat y May 1 next (Dat y May 31) = Dat y June 1 next (Dat y June 30) = Dat y July 1 next (Dat y July 31) = Dat y August 1 next (Dat y August 31) = Dat y September 1 next (Dat y September 30)= Dat y October 1 next (Dat y October 31) = Dat y November 1 next (Dat y November 30) = Dat y December 1 next (Dat y December 31) = Dat (y+1) January 1
next (Dat y m d ) = Dat y m (d+1) dayofweek :: Date -> Day dayofweek d = dayofweeki (datetojulian d mod 7 ) {- where dayofweeki :: Int -> Day dayofweeki 1 = Wedensday dayofweeki 2 = Thursday dayofweeki 3 = Friday dayofweeki 4 = Saturday dayofweeki 5 = Sunday dayofweeki 6 = Monday dayofweeki 0 = Thuesday -} where dayofweeki :: Int -> Day dayofweeki j = toenum ((j+1) mod 7) (-#) :: Date -> Date -> Int (-#) d1 d2 = datetojulian d1 - datetojulian d2 (+#) :: Date -> Date -> Int (+#) d1 d2 = datetojulian d1 + datetojulian d2 (+##) :: Date -> Int -> Date (+##) d1 i = juliantodate (datetojulian d1 + i) (-##) ::Date -> Int -> Date (-##) d1 i = juliantodate (datetojulian d1 - i)