Tuesday, September 27, 2005

Haskell - lecture 3

-- Here's the filter again, this time with "guards".  Guards are like
-- case statements in other languages. The guards are
-- evaluated in order; "otherwise" must come last.
otherFilter :: (a -> Bool) -> [a] -> [a]
otherFilter functionName [] = []
otherFilter functionName (x:xs)
| functionName x = x : otherFilter functionName xs
| otherwise = otherFilter functionName xs

-- This function is intended for use as a filter. It takes one pair
-- as an argument, and returns true if y == 2*x.
-- example use: myFilter doubleSecond [(1,2),(3,4),(5,10)] -> [(1,2),(5,10)]
doubleSecond :: (Int, Int) -> Bool
doubleSecond (x,y)
= y==2 *x

-- Here's another kind of "filter" function: a mapper. It takes a
-- mapping function as an argument, along with a list. It passes
-- each element of the list to the supplied function, and puts the
-- return values in a new list. Example use:
-- myMap (^2) [1,2,3,4] -> [1,4,9,16]
myMap :: (a -> b) -> [a] -> [b]
myMap fn []
= []
myMap fn (x:xs)
= fn x : myMap fn xs

-- The inRange function determines whether a number is
-- in a certain range.
-- The type declaration introduces "Ord". "Ord a" means
-- "any type 'a' that is ordered", i.e. that supports magnitude
-- operators such as > and <. Also notice the new arrow, "=>".
-- It looks like the arrow separates the "interface constraint"
-- on the left with the normal data type declaration on the right.
inRange :: Ord a => a -> a -> a -> Bool
inRange beginning end element
= element >= beginning && element <= end

-- inRange can't be used as a filter directly because it takes 3
-- arguments instead of 1:
-- * myFilter inRange 2 4 [1,2,3,4,5,6] -- wrong
-- However, we can bind the first two arguments, to produce
-- a "new" function that takes only one argument:
-- myFilter (inRange 2 4) [1,2,3,4,5,6] -> [1,5,6]

-- BTW: "zip" takes two lists and makes a list of pairs:
-- zip [1,2,3] ['a','b','c'] -> [(1,'a'),(2,'b'),(3,'c')]
-- zip [1,2,3] "abc" -> [(1,'a'),(2,'b'),(3,'c')]
-- zip [1,2,3,4,5,6] (map (^3) (filter (inRange 2 4) [1,2,3,4,5,6]))
-- -> [(1,8),(2,27),(3,64)]

-- "List comprehensions": a way to generate a finite or infinite
-- list from 1 to 3 parameters. Best explained by example:
-- [1..4] -> [1,2,3,4]
-- [5,4..1] -> [5,4,3,2,1]

-- [5,3.. -5] -> [5,3,1,-1,-3,-5]
-- [2,3.5..7] -> [2.0,3.5,5.0,6.5]
-- [2,3.5..7.5] -> [2.0,3.5,5.0,6.5,8.0] -- strange, eh?
-- [0,10..29] -> [0,10,20]
-- [-2..] -> [-2,-1,0,1,2,...]
-- [2,4..] -> [2,4,6,8,10,12, ...]

-- Here's a list-generating loop construct in Haskell.
ex1 = [x *2 +4 | x <- [1,3..10]]
-- ex1 -> [6,10,14,18,22]
ex2 = [(x,y) | x <- [1..4], y <- [1..4]]
-- ex2 -> [(1,1),(1,2),(1,3),(1,4),(2,1),(2,2),(2,3),(2,4),(3,1),(3,2),(3,3),(3,4),(4,1),(4,2),(4,3),(4,4)]
ex3 = [(x, x*2+y) | x <- [1,2,3], y <- [4,5,6]]
-- ex3 -> [(1,6),(1,7),(1,8),(2,8),(2,9),(2,10),(3,10),(3,11),(3,12)]
tri m = [(i,j) | i <- [0..m], j <- [0..i]]
-- tri 3 -> [(0,0),(1,0),(1,1),(2,0),(2,1),(2,2),(3,0),(3,1),(3,2),(3,3)]
-- :t tri
-- tri :: (Num a, Enum a) => a -> [(a,a)]

-- Tomorrow: computing prime numbers

0 Comments:

Post a Comment

<< Home