Senast Idag Högre ordningens funktioner Listomfattning Strikthet och lat evaluering Strömmar Monadisk I/O Strikt evaluering Icke-strikt evaluering Def: Strikt evaluering innebär att alla parametrars värde är kända när en operator eller funktion anropas. Ex: Funktionsanrop i Java, C, etc Hur beräknas if jobbigt(7) && tungt(47) then...? Vanligen: Man kortsluter jämförelsen. Implementeras för and och or Lat evaluering Testa latheten! Hur beräknas head [..0]? head (qsort longlist)? Lat evaluering i Haskell: Beräkna bara det som behövs Varje uttrck lagras som ett löfte om evaluering vid behov. Vad händer med head (qsort [9,5,4,,2,9])? Instrumentera koden: qsort [] = [] qsort (x : xs) = qsort [(observe e e) e<-xs, e<x] ++ [(observe x x)] ++ qsort [(observe e2 e) e<-xs, e>=x] Testa latheten! Plus och minus med lat evaluering Hugs> head (qsort [4, 5, 4, 3,, 2,9]) >>>>>>> Observations <<<<<< e 3 2 2 x Hugs> Inga värden på e2 det uttrcket har aldrig behövt evalueras Nackdelar: Fördelar: Kan slöa ner ett program (använd då explicit strikt evaluering!) Kan slösa på minne: löftet tar plats Överraskande för den ovetande? Kan snabba upp ett program Undviker onödiga beräkningar. Automatiskt! Erbjuder smarta uttrckssätt.
Valfri strikthet Operatorn ($!). Ersätta f x med f $! x tvingar x att evalueras först. Anpassade funktioner, exv foldr. Strikta datatper, exv data StrictColor = SRGB!r!g!b lagrar inga löften Användning av lat evaluering Vad händer med... ones = ( : ones)? Hugs> ones [... take 0 ones? Hugs> take 0 ones [,,,,,,,,,] lst = ( : map ((+) ) lst)? Hugs> take 0 lst [,2,3,4,5,6,7,8,9,0] Inbggt i Haskell: [..] == lst Mer exempel lst2 = concat (map (\x -> [x,-x]) lst) Hugs> take 0 lst2 [,-,2,-2,3,-3,4,-4,5,-5] Hur ta fram alla tal-par? allpairs = [(x, ) x <- [..], <- [x, (x-)..]] Hugs> take 0 allpairs [(,),(2,2),(2,),(3,3),(3,2),(3,), (4,4),(4,3),(4,2),(4,)] Strömmar: Oändliga listor Tpexemplet: Fibonaccitalen Antag att fibs är listan av Fibonaccital. 2 3 5 8 3 2... fibs + 2 3 5 8 3 2 34... tail fibs 2 3 5 8 3 2 34 55... tail(tail fibs) fibs = ::(elementwiseadd fibs (tail fibs)) where elementwiseadd = zipwith (+) Hugs> take 0 fibs [,,2,3,5,8,3,2,34,55] Pseudoslumptal i Haskell Ett sätt att generera pseudoslumptal: Ström av pseudoslumptal: Måste skickas med överallt. module MinSimulator where import Random prng :: Int -> Int -> [Int] prng n seed = randomrs (0,n-) (mkstdgen seed) Hugs> :load MinSimulator Hugs> take 0 (prng 00 47) [37,92,38,24,22,60,2,24,38,6] Hugs> runsimulation start (prng 00 47) Strömmar i Unix Antag du snabbt måste radera många filer: $ rm -r MinaHemligaMP3 rm: remove write-protected file final_countdown.mp3? rm: remove write-protected file BestOf80s.zip? rm: remove write-protected file trackslistan85.zip?... Två tips:. Använd rm -rf! 2. eller använd es $ es rm -r MinaHemligaMP3 Vad gör es? Programming pearls $ es......tills mottagande programmet avslutas och strömmen stängs. Latheten följer av I/O-buffertar! Klassisk artikelserie i Communications of the ACM, Jon Bentle. Idén: Låt en stjärna lösa ett problem och låt en annan stjärna kritisera den. 986: Given a text file and an integer k, ou are to print the k most common words in the file (and the number of occurrences) in decreasing frequenc. Donald Knuth fick uppdraget.
Knuths lösning Elegant programmering Elegant specialdesignad datastruktur (prefixträd) Noggrant kommenterat och presenterat Kritikern, Doug McIlro, AT&T Bell Labs: Ver few people can obtain the virtuoso services of Knuth [...] to attack problems such as Bentle s from the ground up. But old Unix hands knows instinctivel how to solve this one in a jiff. (McIlro uppfann pipes i Unix.) Strömmar som paradigm McIlros lösning: strömmar i Unix $ cat MittLitteräraVerk.txt tr -cs A-Za-z ˆj # Radbrtningar tr A-Z a-z # Versaler blir gemena sort # Sortera orden uniq -c # Samla ihop och räkna sort -rn # Sortera efter antal head -n 0 # Visa de första 0 Problemet med I/O Uttrcksfullt, snggt Kräver nån sorts lathet God ingenjörskonst! Läs från stdin Skriv till stdout Felmeddelanden till stderr I/O ej funktionellt getchar plockar bort ett tecken från en nån buffert putchar skriver in ett tecken i en buffert. Hur åstadkomma I/O utan sideffekter? Lisp mfl: Fuska! Använd sidoeffekter. Haskell mfl: Kapsla in världen på ett säkert sätt Teater Ansats: Kapsla in världen Pseudokod: main = printstr("rev: ") printstr(reverse(getline))...i imperativt program: Alla delar på världen....i funktionellt program: En funktion är gränssnittet mot världen. Vad vi vill ha: tpe IO a = World -> (a, World) IO-tper är handlingar: Eng: actions Exempel: getchar :: IO Char getchar :: World -> (Char, World) putchar :: Char -> IO () putchar :: Char -> World -> ((), World) iseof getline :: IO Bool :: IO String Sammanfogning av IO Sammanfogning av IO Lim: >>= (och >>) (>>=) :: IO a -> (a -> IO b) -> IO b Exempel : echo :: IO () echo = getchar >>= putchar Tper: a = Char, b = () Lim: >>= (och >>) (>>=) :: IO a -> (a -> IO b) -> IO b Paketering: Konstruktor return return :: a -> IO a Exempel 2: gettwochars :: IO (Char, Char) gettwochars = getchar >>= \c -> getchar >>= \c2 -> return (c, c2)
Vårt teater-exempel: Reverse Sntaktiskt socker: do main = getline >>= (\s -> return (reverse s) >>= (\r -> putstrln r)) main = getline >>= \s -> return (reverse s) >>= \r -> putstrln r Idé: Automatisera sammankopplingen av IO-uttrck Regler: do {x <- e; s e >>= \x -> do {s do e; s e >> do s do e e Exempel: gettwochars = do { c <- getchar; c2 <- getchar; return (c, c2) Lättare att uttrcka sig med do Vårt reverse-program igen: main = do { s <- getline; r <- return (reverse s); putstrln r Eller ännu enklare: main = do { s <- getline; putstrln (reverse s) Exempel: getline getline :: IO [Char] getline = do { c <- getchar; if c == \n then return [] else do { cs <- getline; return (c : cs) Exempel: Räkna tecken och rader Exempel: Räkna tecken och rader Enkel implementation av wc: main = do {(nlines, nchars) <- wc 0 0; putstrln (show nlines ++ "\t" ++ show nchars) wc :: Int -> Int -> IO (Int, Int) wc nlines nchars= do flag <- iseof if flag then return (nlines, nchars) else consumeandcount nlines nchars consumeandcount :: Int -> Int -> IO (Int, Int) consumeandcount nl nc = do { c <- getchar; if (c == \n ) then wc ( + nl) ( + nc) else wc nl (+nc) Hugs> wc 0 0 Hugs> main 6 Hugs> I terminalen: $ runhugs wc.hs bubba 2 2 $ Testa programmet Designprincip för I/O i Haskell Världen Monadisk IO Programlogiken Filer getchar mpreparations Portar getline computeitall stdin/stdout openfile mfilter Grafik readfile iseof m.m.
Lura Haskell... med unsafeperformio Slutsatser? Ett trick för att komma runt monadreglerna: unsafeperformio :: IO a -> a Använd inte för F4 eller på tenta... Peton-Jones: Riktigt obekväm I/O, Once-per-run I/O Debugging: trace :: String -> a -> a trace s x = unsafeperformio (putstrlns s >> return x)... men vi har ju Hugs.Observe! Nackdelar: Fördelar: Krångligt! Tvångströja Separation av I/O och funktionalitet uppmuntras Teoretisk välgjort gör programbevis enklare Monaden Mabe Monaden Mabe Idén: data Mabe a = Just a Nothing Minns lookup: lookup :: Eq a => a -> [(a, b)] -> Mabe b Hugs> lookup [(,"KTH"), (2, "Chalmers")] Just "KTH" Hugs> lookup 5 [(,"KTH"), (2, "Chalmers")] Nothing Bra till enkel felhantering: colorfromstring :: String -> Mabe Color colorfromstring s = s == "red" = Just (RGB 255 0 0) s == "green" = Just (RGB 0 255 0) s == "blue" = Just (RGB 0 0 255) otherwise = Nothing Hugs> colorfromstring "red" Just (RGB 255.0 0.0 0.0) Hugs> colorfromstring "black" Nothing