Craft3e-0.1.0.2: Chapter11.hs
-----------------------------------------------------------------------
--
-- Haskell: The Craft of Functional Programming, 3e
-- Simon Thompson
-- (c) Addison-Wesley, 1996-2011.
--
-- Chapter 11
--
-----------------------------------------------------------------------
-- Functions as values
-- ^^^^^^^^^^^^^^^^^^^
module Chapter11 where
import Prelude hiding (succ,curry,uncurry,flip)
import Chapter10 (getUntil)
import Chapter7 (whitespace)
import Test.QuickCheck
-- A fixity declaration for the forward composition operator, >.>
infixl 9 >.>
-- Function composition and forward composition
-- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-- A composition operator taking its arguments in the opposite order to `.'.
(>.>) :: (a -> b) -> (b -> c) -> (a -> c)
g >.> f = f . g
-- Expressions for functions: lambda abstractions
-- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
addOnes :: [Integer]
addOnes = map (\x -> x+1) [2,3,4]
-- Mapping a list of functions onto a value
mapFuns :: [a->b] -> a -> [b]
mapFuns [] x = []
mapFuns (f:fs) x = f x : mapFuns fs x
-- Two alternative definitions
mapFuns1 fs x = map (\f -> f x) fs
mapFuns2 fs x = map applyToX fs
where
applyToX f = f x
-- A function returning a function, namely the function to `add n to its
-- argument'.
addNum :: Integer -> (Integer -> Integer)
addNum n = (\m -> n+m)
-- The `plumbing' function:
comp2 :: (a -> b) -> (b -> b -> c) -> (a -> a -> c)
comp2 f g = (\x y -> g (f x) (f y))
-- Using the `plumbing' function
plumbingExample = comp2 sq add 3 4
where
sq x = x*x
add y z = y+z
-- Partial Application
-- ^^^^^^^^^^^^^^^^^^^
-- The function multiply multiplies together two arguments.
multiply :: Int -> Int -> Int
multiply x y = x*y
-- Double all elements of an integer list.
doubleAll :: [Int] -> [Int]
doubleAll = map (multiply 2)
-- Another definition of addNum, using partial application to achieve the
-- `function as result'.
addNum' n m = n+m
-- Operator Sections
-- Example of a function defined using partial application and operator sections.
egFun :: [Int] -> [Int]
egFun = filter (>0) . map (+1)
-- Three examples from the text processing functions first seen in Chapter 7.
dropSpace = dropWhile (member whitespace)
dropWord = dropWhile (not . member whitespace)
getWord = takeWhile (not . member whitespace)
-- Auxiliary definitions ...
member xs x = elem x xs
-- Under the hood: curried functions
-- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-- An example function of type (Int -> Int) -> Int
g :: (Int -> Int) -> Int
g h = (h 0) + (h 1)
-- Currying and uncurrying
-- ^^^^^^^^^^^^^^^^^^^^^^^
-- An uncurried function to multiply together the two itegers in a pair.
multiplyUC :: (Int,Int) -> Int
multiplyUC (x,y) = x*y
-- Turn an uncurried function into a curried version,
curry :: ((a,b) -> c) -> (a -> b -> c)
curry g x y = g (x,y)
-- and vice versa.
uncurry :: (a -> b -> c) -> ((a,b) -> c)
uncurry f (x,y) = f x y
-- Zip property
prop_zip :: [(Integer, Integer)] -> Bool
prop_zip xs = uncurry zip (unzip xs) == xs
-- Defining higher-order functions
-- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-- Using the operators
-- Compose a function with itself: apply it twice, in other words.
twice :: (a -> a) -> (a -> a)
twice f = (f . f)
succ :: Int -> Int
succ n = n+1
-- We can generalize twice so that we pass a parameter giving the number
-- of times the functional argument is to be composed with itself:
iter :: Int -> (a -> a) -> (a -> a)
iter n f
| n>0 = f . iter (n-1) f
| otherwise = id
-- An alternative definition of iter:
iter' n f = foldr (.) id (replicate n f)
-- Using local definitions
addNum2 :: Integer -> Integer -> Integer
addNum2 n = addN
where
addN m = n+m
addNum3 n = let
addN m = n+m
in
addN
-- Lambda abstractions
flip' :: (a -> b -> c) -> (b -> a -> c)
flip' f = \x y -> f y x
-- Change the order of arguments of a two argument curried function.
flip :: (a -> b -> c) -> (b -> a -> c)
flip f x y = f y x
-- Mystery function from "Point-free programming"
puzzle = (.) (.)
-- Final examples
-- Double all integers in a list,
doubleAll' :: [Int] -> [Int]
doubleAll' = map (*2)
-- get the even numbers in a list of integers,
getEvens :: [Int] -> [Int]
getEvens = filter ((==0).(`mod` 2))
-- get a word from the start of a string.
getWord' = getUntil (`elem` whitespace)
-- Verification and general functions
-- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
prop_mf p f =
\xs -> (filter p . map f) xs == (map f . filter (p . f)) xs