From 26cfef70c8344f3154f3b172a55d4f908d0a98b1 Mon Sep 17 00:00:00 2001 From: Michael Zhang Date: Thu, 28 Jan 2021 02:26:32 -0600 Subject: [PATCH] ch1 progress --- ch01.lhs | 162 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 162 insertions(+) diff --git a/ch01.lhs b/ch01.lhs index 6c037e5..9d5172c 100644 --- a/ch01.lhs +++ b/ch01.lhs @@ -1,6 +1,9 @@ Chapter 1: Functional Programming === +> import Prelude hiding (foldl, foldr) +> import Control.Exception + Exercise 1.2 --- @@ -36,3 +39,162 @@ number of times in the rest of this book. Give appropriate definitions. > > single [x] = True > single _ = False + +Exercise 1.4 +--- + +Write down a definition of reverse that takes linear time. One possibility is to use a foldl. + +> -- This takes linear time because the list basically builds up backwards +> reverse :: [a] -> [a] +> reverse = foldl (\a x -> x : a) [] + +Exercise 1.5 +--- + +Express both map and filter as an instance of foldr. + +> map2 :: (a -> b) -> [a] -> [b] +> map2 f = foldr (\x a -> f x : a) [] +> +> filter2 :: (a -> Bool) -> [a] -> [a] +> filter2 f = foldr (\x a -> if f x then x : a else a) [] + +Exercise 1.6 +--- + +Express `foldr f e . filter p` as an instance of foldr. + +> composed :: (a -> b -> b) -> (a -> Bool) -> b -> [a] -> b +> composed f p e = foldr f e . filter p +> +> composed2 :: (a -> b -> b) -> (a -> Bool) -> b -> [a] -> b +> composed2 f p = foldr (\x a -> if p x then f x a else a) + +Exercise 1.7 +--- + +The function takeWhile returns the longest initial segment of a list all of +whose elements satisfy a given test. Moreover, its running time is proportional +to the length of the result, not to the length of the input. Express takeWhile +as an instance of foldr, thereby demonstrating once again that a foldr need not +process the whole of its argument before terminating. + +> -- I think the fact that foldr doesn't consume the whole thing here is only +> -- due to laziness, since foldr builds up the expression from the back. +> takeWhile :: (a -> Bool) -> [a] -> [a] +> takeWhile f = foldr (\x a -> if f x then x : a else []) [] + +Exercise 1.8 +--- + +The Data.List library contains a function dropWhileEnd which drops the longest +suffix of a list all of whose elements satisfy a given boolean test. For +example, + +> _ = dropWhileEnd even [1, 4, 3, 6, 2, 4] == [1, 4, 3] + +Define dropWhileEnd as an instance of foldr. + +> dropWhileEnd :: Eq a => (a -> Bool) -> [a] -> [a] +> dropWhileEnd f = foldr (\x a -> if f x && a == [] then [] else x : a) [] + +Exercise 1.9 +--- + +An alternative definition of foldr is + +> foldr f e xs = if null xs then e else f (head xs) (foldr f e (tail xs)) + +Dually, an alternative definition of foldl is + +> foldl f e xs = if null xs then e else f (foldl f e (init xs)) (last xs) + +where last and init are dual to head and tail. What is the problem with this +definition of foldl? + +> -- init and last are both O(n) operations since they require traversing to +> -- the end as opposed to head and tail which are O(1) which means overall this +> -- alternate definition of foldl is really expensive. + +Exercise 1.10 +--- + +Bearing the examples + +> -- foldr (⊕) e [x, y, z] == x ⊕ (y ⊕ (z ⊕ e)) +> -- foldl (⊕) e [x, y, z] == ((e ⊕ x) ⊕ y) ⊕ z + +in mind, under what simple conditions on (⊕) and e do we have + +> -- foldr (⊕) e xs = foldl (⊕) e xs + +for all finite lists xs? + +> -- (⊕) just needs to be associative and e the identity. +> +> -- This will give us x ⊕ (y ⊕ (z)) for foldr and (x ⊕ y) ⊕ z for foldl, which +> -- still preserves the order of x, y, and z so if (⊕) is associative then +> -- the statements are equivalent. + +Exercise 1.11 +--- + +Given a list of digits representing a natural number, construct a function +integer which converts the digits into that number. For example, + +> _ = integer [1, 4, 8, 4, 9, 3] == 148493 + +Next, given a list of digits representing a real number r in the range 0 <= r < +1, construct a function fraction which converts the digits into the +corresponding fraction. For example, + +> _ = fraction [1, 4, 8, 4, 9, 3] == 0.148493 + +> integer :: [Int] -> Int +> integer = foldl (\a x -> 10 * a + x) 0 +> +> fraction :: [Int] -> Double +> fraction = (/ 10) . foldr (\x a -> fromIntegral x + a / 10) 0 + +Exercise 1.12 +--- + +Complete the right hand sides of: + +> -- map (foldl f e) . inits = ??? +> -- map (foldr f e) . tails = ??? + +> -- TODO + +Exercise 1.13 +--- + +Define the function + +> apply :: Int -> (a -> a) -> a -> a + +that applies a function a specified number of times to a value. + +> apply 0 f x = x +> apply n f x = apply (n - 1) f (f x) + +Exercise 1.14 +--- + +Can the function inserts associated with the inductive definition of perms be +expressed as an instance of foldr? + +> -- TODO + +Exercise 1.15 +--- + +Give a definition of remove for which + +> -- perms3 [] = [[]] +> -- perms3 xs = [x : ys | x <- xs, y <- perms3 (remove x xs)] + +computes the permutations of a list. Is the first clause necessary? What is the +type of perms3, and can one generate the permutations of a list of functions +with this definition?