CS 11 Haskell track: lecture 2This week:More basicsAlgebraic datatypesPolymorphismList functionsList comprehensionsType synonymsIntroduction to input/output (I/O)Compiling standalone programslet and where (1)let:factorial :: Int -> Intfactorial n = let iter n r = if n == 0 then r else iter (n-1) (n*r) in iter n 1let and where (2)where:factorial :: Int -> Intfactorial n = iter n 1 where iter n r = if n == 0 then r else iter (n-1) (n*r)let and where (3)where (nicer):factorial :: Int -> Intfactorial n = iter n 1 where iter 0 r = r iter n r = iter (n-1) (n*r)Lambda (λ) expressionsUsed to create anonymous functions\<pattern> -> <expr>Usually just e.g.\x -> 2*x\x y -> x + yPattern example:map (\(x, y) -> x + y) [(1, 2), (4, 1), (-3, 20)] [3, 5, 17]Operator slicesInstead of writing\x -> x + 1you can just write:(+1)Similarly, instead of writing\x -> 2 * xyou can write:(2*)Example:map (2*) [1..5] [2,4,6,8,10]case expressions (1)Used for pattern matches within expressionsSyntax: case <expr> of <pattern1> -> <expr1> <pattern2> -> <expr2> ...If want a default, use _ (wildcard) as last pattern_ matches anything and throws the value awaycase expressions (2)Example:zeros :: [Int] -> [Int]zeros lst = case lst of (_ : rest) -> 0 : zeros rest [] -> [](Not terribly useful)Could also use pattern matching on function itselfAlgebraic datatypes (1)Often want to define own data types to express the structure of some kind of dataOften the data can be in one of several alternative formsCreate an algebraic datatype for thisMany already provided in standard library AKA the PreludeAlgebraic datatypes (2)Example:data MaybeInt = NoInt | AnInt Intlet (x, y, z) = (NoInt, AnInt 2, AnInt 5)N.B. type names and data constructor names must start with capital letter!Type of (x, y, z)?(MaybeInt, MaybeInt, MaybeInt)Algebraic datatypes (3)N.B. Can't define new datatypes in ghciBest to put into file and load using :l file.hsMight want to have a more general type than MaybeIntthe Maybe concept works just as well for any typeexpresses concept of "not sure if will have anything, but if we do it'll be of this type"Don't want to have to define MaybeInt, MaybeFloat, MaybeString... All have same structurePolymorphism (1)Data types can be parameterized over other typesSo for Maybe example we have (built-in):data Maybe a = Nothing | Just aHere a is a type variableWritten with an initial lower-case letterPolymorphism (2)Types:Nothing :: Maybe aJust 10 :: Maybe IntJust "hi there!" :: Maybe StringJust :: a -> Maybe aParameterized type constructors are also functions! map Just [1..5] [Just 1, Just 2, ..., Just 5]Examplelength :: [a] -> Intlength [] = 0length (x:xs) = 1 + length xsWorks for any listMore pattern matchingPattern matching on algebraic data types:foo :: Maybe Int -> Intfoo Nothing = 0foo (Just x) = 1 + xbar :: Maybe (Maybe String) -> Stringbar Nothing = "None"bar (Just Nothing) = "Sorta"bar (Just (Just x)) = "Yes: " ++ x-- N.B. ++ concatenates listsListsLists behave as if they were defined like this:-- WARNING: Bogus pseudo-Haskell:data [a] = [] | a : [a]Note that (:) is a data constructor just like JustPattern matching on lists:head :: [a] -> Maybe ahead (x : _) = Just xhead [] = NothingN.B. the parentheses are important!As-patterns (@-patterns)You can assign a name to a pattern while also matching its partsExample:foo :: Maybe Int -> Maybe Intfoo x@(Just y) = xfoo Nothing = NothingThis looks useless now, but becomes useful when patterns get more complicatedList functions and the PreludeThe Haskell Prelude is where the most basic functions are definedAlways available to the programmerIncludes many useful list functionsOften fairly obvious what they do from the type signatureUseful list functionsExamples:(++) :: [a] -> [a] -> [a] –- list concatmap :: (a -> b) -> [a] -> [b]filter :: (a -> Bool) -> [a] -> [a]head :: [a] -> a -- not like one we definedfoldr :: (a -> b -> b) -> b -> [a] -> brepeat :: a -> [a]cycle :: [a] -> [a]mapmap f lst applies f to each element of lst, returning the resultsmap :: (a -> b) -> [a] -> [b]map f (x:xs) = f x : map f xsmap _ [] = []map (/2) [1..3] [0.5, 1.0, 1.5]foldr ("fold right")foldr op z [x1,x2, ... xn] reduces the list by computingx1 `op` (x2 `op` ... (xn `op` z))Definition left as "exercise for student"sum :: [Int] -> Intsum = foldr (+) 0Pop quiz: what is foldr (:) [] ?More list functions (1)concat :: [[a]] -> [a]take :: Int -> [a] -> [a]drop :: Int -> [a] -> [a]elem :: a -> [a] -> Bool-- usually written as -- 5 `elem` [1..10]zip :: [a] -> [b] -> [(a, b)]More list functions (2)Many more list functions in PreludeUse Prelude functions instead of reimplementing them yourselfread Prelude docs (linked from web pages)List comprehensions (1)List comprehensions are a convenient way to create lists with particular propertiesfibs :: [Integer]fibs = 0:1:[x+y|(x,y) <- zip fibs (tail fibs)]Infinite list of fibonacci numbersTo get first 20, dotake 20 fibsList comprehensions (2)General structure:[<expr> | pattern <- source ..., filter ...]Examples:[x | x <- [1..1000], x `mod` 2 == 1][(x, y) | x <- [1..10], y <- [1..10], x + y == 10]Type synonymsCan create a synonym for a typeCompiler can't always figure out the right name to use (e.g. in ghci) , but it triesExamples:type String = [Char] -- in the Preludetype Label = Stringtype Point = (Double, Double)Introduction to I/O (1)Input/output is odd in HaskellCan't have side effects!Input/output actions are values of type IO a, where a is the type of the action's resultActions with no useful result have type IO ()() is the sole instance of the unit typeIntroduction to I/O (2)Examples:putStr :: String -> IO ()putStrLn :: String -> IO ()getLine :: IO Stringprint :: a -> IO ()Our first encounter with dreaded MonadsMuch more to say about this in futureEntire program is a computation of type IO ()Compiling standalone programsCreate a main function with type IO ()Compile the program with% ghc –o progname filename.hsRun the program:% prognameHit ctrl-C if the program doesn't terminateNext weekMuch more on I/OType
View Full Document