Haskell - function returns an empty character

I am trying to create a function that removes every nth element from a string.

dropEvery :: String -> Int -> String dropEvery str n = map (\(char, indx) -> if indx `mod` n /= 0 then char else ' ') (zip str [1..]) 

Now it just replaces every nth element with a space, but what should I put after "else" if I want it to return an "empty char". I understand that such a thing does not exist in Haskell, so the question is, how should I tell Haskell not to return anything and just move on to the next char?

+6
source share
3 answers

You cannot do this only with map ; by definition, it cannot change the length of the collection used. However, you can get this to work without too many changes by switching to concatMap . This function requires your function to display a list and then merge all the results. All you have to do is

 dropEvery str n = concatMap (\(char, indx) -> if indx `mod` n /= 0 then [char] else []) (zip str [1..]) 
+7
source

map preserves the structure of the list, and your operations modify it by deleting elements. This means you cannot use map , but you can use mapMaybe , which allows you to provide a function that returns Nothing for the elements you want to remove from the output:

 import Data.Maybe (mapMaybe) dropEvery str n = mapMaybe (\(char, indx) -> if indx `mod` n /= 0 then Just(char) else Nothing) (zip str [1..]) 
+5
source

You can do it without mod . I'm going to reverse the order of the arguments to make this more idiomatic.

 dropEvery :: Int -> [a] -> [a] dropEvery n xs = map fst . filter ((/= n) . snd) $ zip xs (cycle [1..n]) 

If speed is critical, it is probably most efficient to use this technique with explicit recursion or foldr . Something like that:

 dropEvery n xs = foldr go (`seq` []) xs n where go _ r 1 = rn go xrk = x : r (k - 1) 
+3
source

All Articles