Skip to content

Commit 94ce28d

Browse files
committed
Part 1 Chapter 7 Exercise 6, part 3.
1 parent 548cd83 commit 94ce28d

File tree

1 file changed

+56
-1
lines changed

1 file changed

+56
-1
lines changed

part1_chapter7_exercise6/Main.hs

Lines changed: 56 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,12 @@ main = do
1818
putStrLn "chop8' [1, 2, 3, 4, 5, 6, 7, 8, 9]"
1919
putStrLn . show $ chop8' [1, 2, 3, 4, 5, 6, 7, 8, 9]
2020

21+
putStrLn "map (+1) [1, 2, 3]"
22+
putStrLn . show $ map (+1) [1, 2, 3]
23+
24+
putStrLn "map' (+1) [1, 2, 3]"
25+
putStrLn . show $ map' (+1) [1, 2, 3]
26+
2127
unfold :: (a -> Bool) -> (a -> a) -> (a -> a) -> a -> [a]
2228
unfold predicate headFunction tailFunction x
2329
| predicate x = []
@@ -31,4 +37,53 @@ chop8 [] = []
3137
chop8 bits = (take 8 bits) : (chop8 (drop 8 bits))
3238

3339
chop8' :: [Bit] -> [[Bit]]
34-
chop8' = unfold null (take 8) (drop 8)
40+
chop8' = unfold null (take 8) (drop 8)
41+
42+
-- This one was quite confusing to me, so I thought I would leave some comments to complement the implementation.
43+
-- The author asks readers to implement "map f". "map" signature is:
44+
--
45+
-- map :: (a -> b) -> [a] -> [b]
46+
--
47+
-- which translates to (for lists, that is): every item in list [a] gets mapped from type a to type b and then
48+
-- returned as [b].
49+
--
50+
-- Now with that in mind, does it really makes sense to apply "unfold" here? Is the function not supposed to build a list
51+
-- using the starting value and the functions provided? If not, I'm not sure what really is required. If so, though,
52+
-- the type signature defined by the regular "map" is going to make:
53+
-- the implementation unnecessarily complicated
54+
-- map and map' are not going to be interchangable.
55+
--
56+
-- My initial thought was to implement function:
57+
--
58+
-- map' :: (a -> b) -> [a] -> [b]
59+
--
60+
-- with the signature identical to the regular "map" (just a different implementation) so that both can be used interchangeably.
61+
-- It took me a while before I realized that it is probably more tricky than it should be.
62+
-- This is when I started looking for other solutions, just to get an idea how people interpret the task.
63+
-- What I found mademe even more confused. Examples:
64+
--
65+
-- 1. https://github.com/evturn's implementaion: https://github.com/evturn/programming-in-haskell/blob/master/07-higher-order-functions/07.9-exercises.hs
66+
--
67+
-- map' p f xs = unfold p f f xs
68+
--
69+
-- the type here is:
70+
--
71+
-- map' :: (a -> Bool) -> (a -> a) -> a -> [a]
72+
--
73+
-- So as you can see, it doesn't match the original "map"'s type and the input argument (second last "a") gets "unfolded" into [a].
74+
--
75+
-- 2. Another example I found is the one by https://github.com/RoccoMathijn: https://github.com/RoccoMathijn/programming-in-haskell/blob/master/chapter07.hs
76+
--
77+
-- map' :: (a -> b) -> [a] -> [b]
78+
-- map' f = unfold (null) (f.head) (tail)
79+
--
80+
-- But this again is not intercangeable with the original "map" as b is simply [a], so the result is really [[a]].
81+
--
82+
-- After more time than I'd like to admit, I finally figured out the implementation which is interchangeable with the original "map".
83+
-- Terribly inefficient, but I believe it answers the exercise's question precisely.
84+
85+
map' :: (a -> b) -> [a] -> [b]
86+
map' f = concat . unfold null (listify . f . head) (tail)
87+
88+
listify :: a -> [a]
89+
listify x = [x]

0 commit comments

Comments
 (0)