Home > Mobile >  How do I get the index of empty lines in a string in Haskell using pattern matching without importin
How do I get the index of empty lines in a string in Haskell using pattern matching without importin

Time:11-10

For example:

nLn "This\n\nis an\nexample\n\n" == [2,5,6]
nLn "" == [1]

I have tried this but it doesn't seem to be working, why is that?

nLn :: Integral a => String -> [a]
nLn "" = [1]
nLn (x:xs) = [n | n <- lineBr (x:xs)]
    where
        lineBr (x:y:xs)
            |x == y && y =='\n' = 1
            |otherwise = 1  lineBr (y:xs)
        lineBr [x] = 0

CodePudding user response:

I have to admit that I don't completely get where you are going with your attempted solution. The reason that it doesn't work, i.e., that is gets rejected by the type checker, is that while your helper function lineBr returns a single number, it is used by nLn as if it returns a list, i.e., as the generating expression in a list comprehension.

Here's an implementation (with a simpler type and an arguably more descriptive name) that does the trick:

indicesOfEmptyLines :: String -> [Int]
indicesOfEmptyLines = go 1 True
  where
    go _ False ""          = []
    go i True ""           = [i]
    go i False ('\n' : cs) = go (i   1) True cs
    go i True ('\n' : cs)  = i : go (i   1) True cs
    go i _ (c : cs)        = go i False cs

The idea is to have the heavy lifting done by a helper function go that will iterate over the characters in the input string. The helper function takes two additional arguments: the index of the line that it is currently processing (I followed your example and used 1-based indexing) and a Boolean indicating whether the currently processed line can still be empty.

We consider five cases:

  1. If we reach the end of the string and the current line is known not to be empty, we know we are done and we have no more indices to report. Hence, we produce the empty list.
  2. If we reach the end of the string and the current line can still be empty (i.e., we have not encountered any characters on it yet), we know we are done and that the last line was in fact an empty line. Hence, we produce a singleton list containing the index of the last line.
  3. If we encounter a newline character and the current line is known not to be empty, we advance the index, acknowledge that the next line can still be empty (as we have not encountered any characters on it yet), and we proceed by processing the remainder of the string.
  4. If we encounter a newline character and the current line can still be empty, then we know that the current line is in fact empty and we prepend the current index to any indices that the recursive call to go will produce. We advance the index, acknowledge that the next line can still be empty, and we proceed by processing the remainder of the string.
  5. If we encounter any other character than a newline, we know that the current line cannot be empty (hence, we pass False to the recursive call to go) and we proceed by processing the remainder of the string.

Seeing it in action:

> indicesOfEmptyLines "This\n\nis an\nexample\n\n"
[2,5,6]

> indicesOfEmptyLines ""
[1]
  • Related