An Introduction to Programming in Haskell Gabriel J. Ferrer Hendrix College
Overview Functional programming Property testing Iteration Type system I/O
Installation Go to: http://www.haskell.org/ Download the Haskell Platform Windows, Mac, Linux are all available Interactive interpreter runs in web browser
Functional Programming Computations are mathematical expressions Functions are first-class values Referential Transparency
A First Haskell Function fact :: Integer -> Integer fact n n == 0 = 1 otherwise = n * fact (n - 1)
A Calculation numitems :: [a] -> Integer numitems [] = 0 numitems (x:xs) = 1 + numitems xs
A Transformation timesn :: [Int] -> Int -> [Int] timesn [] _ = [] timesn (x:xs) n = (x * n):(timesn xs n)
Filtering positive :: [Int] -> [Int] positive [] = [] positive (x:xs) x > 0 = x:(positive xs) otherwise = positive xs
Write these functions: addup :: [Int] -> Int negateall :: [Int] -> [Int] alleven :: [Int] -> Bool keepevens :: [Int] -> [Int]
Property Testing Write a formal specification in Haskell Generate random tests of the specification import Test.QuickCheck
Some Properties prop_doublenegate :: [Int] -> Bool prop_doublenegate l = negateall (negateall l) == l prop_checkevens :: [Int] -> Bool prop_checkevens l = alleven $ keepevens l prop_subaddup :: [Int] -> Bool prop_subaddup l = addup l + addup (negateall l) == 0
Iteration Functions are first-class values Define general iteration structures taking functions as arguments
Examples Revisited fact :: Integer -> Integer fact n = foldr (*) 1 [2..n]
Examples Revisited numitems :: [a] -> Integer numitems l = foldr inc 0 l where inc _ total = total + 1
Examples Revisited timesn :: [Int] -> Int -> [Int] timesn l n = map (n*) l
Examples Revisited positive :: [Int] -> [Int] positive l = filter (\n -> n > 0) l
What is foldr? foldr :: (a -> b -> b) -> b -> [a] -> b foldr f z [] = z foldr f z (x:xs) = f x (foldr f z xs)
What is map? map :: (a -> b) -> [a] -> [b] map f l = foldr step [] l where step x xs = (f x):xs
What is filter? filter :: (a -> Bool) -> [a] -> [a] filter p l = foldr step [] l where step x xs p x = x:xs otherwise = xs
Using higher-order functions: addup :: [Int] -> Int negateall :: [Int] -> [Int] alleven :: [Int] -> Bool keepevens :: [Int] -> [Int]
List Comprehensions timesn :: [Int] -> Int -> [Int] timesn l n = [x * n x <- l] positive :: [Int] -> [Int] positive l = [x x <- l, x > 0]
A Nested Loop points :: Int -> Int -> [(Int,Int)] points w h = [(x,y) x <- [1..w], y <- [1..h]]
Using list comprehensions: negateall :: [Int] -> [Int] keepevens :: [Int] -> [Int] halves :: [Int] -> [Int] halfevens :: [Int] -> [Int]
More about lists Infinite lists [1..] [1,3..] [2,4..] take, drop
Customized Infinite Lists iterate (1+) 0 iterate (2*) 1
Using Infinite Lists facts :: [Integer] facts = 1:[n*f (f,n) <- zip facts [1..]] facts!! 5
Fibonacci Numbers fibs :: [Integer] fibs = 0 : 1 : [x+y (x,y)<- zip fibs $ tail fibs]
zipwith facts :: [Integer] facts = 1:zipWith (*) facts [1..] fibs :: [Integer] fibs = 0:1:zipWith (+) fibs (tail fibs)
Data Types data Coin = Heads Tails toss :: Coin -> Coin toss Heads = Tails toss Tails = Heads
Type Classes class Eq a where (==), (/=) :: a -> a -> Bool x /= y = not (x == y) instance Eq Coin where Heads == Heads = True Tails == Tails = True Heads == Tails = False Tails == Heads = False
deriving data Coin = Heads Tails deriving (Eq, Show)
Write these functions: tossn :: Int -> Coin -> [Coin] numof :: (Eq a) => a -> [a] -> Int -- Example: numh :: Int -> Int numh n = numof Heads $ tossn n Heads
Binary Tree data Tree a = Node a (Tree a) (Tree a) Sentinel deriving (Eq, Show)
The Ord class class (Eq a) => Ord a where (<),(<=),(>=),(>) :: a -> a -> Bool max, min :: a -> a -> a
Tree Exercise empty :: Tree a -> Bool add :: (Ord a) => a -> Tree a -> Tree a has :: (Ord a) => Tree a -> a -> Bool
Arrays import Data.Array fibarray n = a where a = array (0,n) ([(0, 1), (1, 1)] ++ [(i, a!(i-2) + a!(i-1)) i <- [2..n]])
Monads Side effects disrupt referential transparency Fatal for lazy evaluation Solution: Package up totally ordered side effects
IO Monad main :: IO () main = do x <- getline putstrln x
Random Numbers import System.Random main = do gen <- newstdgen let ns = randoms gen :: [Int] print $ take 10 ns
Mutable Arrays import Control.Monad import Control.Monad.ST import Data.Array.ST fib8 n = runst $ do arr <- newarray (0, n) 0 :: ST s (STArray s Integer Integer) writearray arr 0 0 writearray arr 1 1 form_ [2..n] $ \i -> do val1 <- readarray arr (i - 2) val2 <- readarray arr (i - 1) writearray arr i $ val1 + val2 result <- readarray arr n return result
Resources www.haskell.org hackage.haskell.org Akin to CPAN in the Perl world http://book.realworldhaskell.org/read/ http://ozark.hendrix.edu/~ferrer/ presentations/