Both exercises have a common pattern of "filter by a transformed list, then untransform the result". See skip
and localMaxima
.
-- exercise 1
skips :: [a] -> [[a]]
skips xs = map (\n -> skip n xs) [1..(length xs)]
skip :: Integral n => n -> [a] -> [a]
skip n xs = map snd $ filter (\x -> (fst x) `mod` n == 0) (zip [1..] xs)
--exercise 2
isLocalMaximum :: Integral a => (a,a,a) -> Bool
isLocalMaximum (a,b,c) = b > a && b > c
sliding3 :: [a] -> [(a,a,a)]
sliding3 xs@(a:b:c:_) = (a,b,c) : sliding3 (tail xs)
sliding3 _ = []
localMaxima :: Integral a => [a] -> [a]
localMaxima xs = map proj2 $ filter isLocalMaximum (sliding3 xs)
where proj2 (_,b,_) = b
-- *Main> filter isLocalMaximum (sliding3 [1,5,2,6,3])
-- [(1,5,2),(2,6,3)]
My instincts say that I could implement both of these something like this:
localMaxima' :: Integral a => [a] -> [a]
localMaxima' xs = filterBy isLocalMaximum sliding3 xs
if only I could implement filterBy
filterBy :: (b -> Bool) -> ([a] -> [b]) -> [a] -> [a]
filterBy p f as = as'
where indexedAs = zipWith (,) [0..] as
indexedBs = zipWith (,) [0..] (f as)
indexedBs' = filter p indexedBs -- doesn't typecheck; how can we teach p about the tuples?
indexes = map fst indexedBs
as' = map (\i -> snd (indexedAs !! i)) indexes
It's also slower than just writing out a fold. Is this all a bad idea? I've always considered fold
a low level recursion operator and always try to structure in terms of higher level map
and filter
but maybe I am misunderstanding.
My Haskell level is: understand LYAH but not written much code.
This is a homework to CIS 194 (2013 version) (though I am not taking the class, I am working through the material on my own)