2
\$\begingroup\$

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)

\$\endgroup\$

1 Answer 1

1
\$\begingroup\$

Exercise 1

If you have a lambda (or any function) of type (a,b)->c, instead of writting it like this (\x->...), you can write it like this (\(x,y)->...). It will remove the need of calling fst like in your skip function. You should change the name skip too, because it already exist in the prelude and it's kinda unclear because they have different meaning. I would call it something like skipEvery

Exercise 2

as is a keyword in Haskell, used for module importation. It will compile if you use it as a variable, but if you a text editor with syntax highlighting, it will be weird

My instincts say that I could implement both of these something like this:

localMaxima' :: Integral a => [a] -> [a] 
localMaxima' xs = filterBy isLocalMaximum sliding3 xs

Your instinct wasn't wrong, but there is an alternative to filterBy, which is mapMaybe. The resulting code would be something like this

whenMaybe p x = if p x then Just x else Nothing
localMaxima' = mapMaybe (whenMaybe isLocalMaximum) . sliding3

You should use zip instead of zipWith (,), because both operations are equivalent

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.