Föreläsning 3 i Programmeringsparadigm Repetition : Att definiera en funktion i Haskell. Labhäftet p 11. Exempel : "Korrekta" (Gratis, 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 -} Moduler, Abstrakta Data Typer (ADT). Exempel: ADT Complex och ADT Date (se några sidor fram) som finns på /info/progp02/haskelllectures/f3. Där finns även en del andra program. Något om typklasser och "overloading" (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.) Schacklabben, introduktion och de två första stegen. Föreläsningen följer sidorna från sidan 22 till sida 27 i labbhäftet.
Listprogrammering i funktionella språk. Polymorfism. Tupler. OBS! C&K definierar först IntList, sedan listor som introduserar slutligen sedan de inbyggda data List a = Nil data [a ] = [] Cons a (List a) a : [a] Listor har alltså konstruerararna [] :. Konstruerarna kan används i mönster. [1,2] == 1:2:[] Vad utmärker rekursiva datatyper? Del av värden i typen av samma typ. Kan vara "godtyckligt stora". Tupler, t ex par : data (a, b) = (a,b). Konstruerare (, ). Konstruerarna kan används i mönster. Tupler och listor. Likheter och skillnader. (C&K p 17, Fokker p 52). Exempel: sum (Fokker p 13), prod (C&K p 26 ), length (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 (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. (++) (Fokker p 39, C&K p 28 ), zip (Fokker p 56 ) Strängar är listor (labhäftet p 17, Fokker 45). "hej" == [ h, e, j ] == h : e : j :[] Allt man kan göra, alla funktioner för listor användbara för strängar. 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. I C&K bör nu de mesta i kapitel 1, 3, 4, 8 kunna läsas och förstås, Mer om listor i Fokker avsnitt 3.1 Lists, men vi hoppar tills vidare över 3.1.3 Higer order functions on list. Vidare i Fokker delar av avsnitt 3.2 Special lists; avsnitten 3.2.1 Strings 3.2.2, Characters 3.2.2, 3.2.3 Functions on characacters and strings. Till slut kan man nu också läsa början av 3.3 Tuples; avsnitten 3.3.1 Use of tuples, 3.3.2 Type definitons, 3.3.4 Tuples and lists och 3.4.5 Special uses of data definitons. Hur hittar man "fördefinierade namn (funktioner)"? 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å detta häfte finns en lista över några funktioner. Man kan titta på och söka i preluden ( skriven i Haskell till största delen) med emacs, filnamn /pkg/hugs98/dec01/os/share/hugs/lib/prelude.hs (i ingressen när du startar hugs.) Övningar i Fokker (sid 18, sid 19, sid 63). 1.4, 1.7, 1.8, 1.10, 1.13, 1.14, 3.1, 3.3 3.10. Övningar i C&K., 1.1.3 alla p 6, 3.7 alla p 19
Signaturbild och moduler för ADT Complex och ADT Date Double im re cartesian polar +$ -$ *$ /$ absz arg Complex String show Pil Fet stil Cirkel funktion exporteras symboliserar alla värden i en datatyp module Complex -- på /info/progp02/haskelllectures/f3/complex.hs (Complex, polar, -- Constructor Double -> Double -> Complex r * exp (fi) cartesian, -- Constructor Double -> Double -> Complex a + ib arg, -- Selector Complex -> Double arg(z) absz, -- Selector Complex -> Double z re, -- Selector Complex -> Double Re(z) im, -- Selector Complex -> Double Im(z) (+$), -- Complex -> Complex -> Complex z1 + z2 (-$), -- Complex -> Complex -> Complex z1 - z2 (*$), -- Complex -> Complex -> Complex z1 * z2 (/$) -- Complex -> Complex -> Complex z1 / z2 ) where data Complex = CompPol Double Double --polar implementation CompCart Double Double --cartesian implementation deriving Show polar :: Double -> Double -> Complex polar = CompPol cartesian :: Double -> Double -> Complex cartesian = CompCart
arg :: Complex -> Double arg (CompPol _ fi) = fi arg (CompCart 0.0 b) b>= 0 = 0.5*pi otherwise = -0.5*pi arg (CompCart a 0.0) a>= 0 = 0.0 otherwise = -pi arg (CompCart a b) a>= 0 = atan (b/a) otherwise = atan (b/a) + pi absz :: Complex -> Double absz (CompPol r _) = r absz (CompCart a b) = sqrt (a*a + b*b) re :: Complex -> Double re (CompPol r fi ) = r * cos fi re (CompCart a _ ) = a im :: Complex -> Double im (CompPol r fi ) = r * sin fi im (CompCart _ b ) = b (+$) :: Complex -> Complex -> Complex (+$) z1 z2 = cartesian (re z1 + re z2) (im z1 + im z2) (-$) :: Complex -> Complex -> Complex (-$) z1 z2 = cartesian (re z1 - re z2) (im z1 - im z2) (*$) :: Complex -> Complex -> Complex (*$) z1 z2 = polar (absz z1 * absz z2) (arg z1 + arg z2) (/$) :: Complex -> Complex -> Complex (/$) z1 z2 = polar (absz z1 / absz z2) (arg z1 - arg z2) ----------------------------------------------------------------------------------------------------------------------------- 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)
Date yearjan0tojulian Bool 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
Exporterade namn från Prelude (dvs "fördefinierade namn") : Detta ä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 :t <namnet> i hugs ) förstår vad namnet står för. För att finna namnen i filen kan man använda Search i emacs :..> emacs /pkg/hugs98/dec01/os/share/hugs/lib/prelude.hs & 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