-2

I do not know what is the problem with my code. Can I get some help to understand it ?

Use longestChain to see how long the longest string in a text is made up of identical characters!

Examples:
 longestChain "2111234" == 3
 longestChain "0023212212222" == 4
 longestChain "23232323232" == 1
 longestChain "+++++!!!-------" == 7
longestChain :: String -> Int
longestChain (x:y:xs)
 | x == y = 1 + longestChain xs
 | otherwise = longestChain (y:xs)
topi12
  • 37
  • 5
  • 1
    there's lots of things wrong with your code, and you *should have included* your test calls and the output and / or ***error messages*** they produce. you should make at least this minimal amount of effort, like _try_ your code in GHCi (or some other REPL). not just copy-paste it here. – Will Ness Nov 03 '21 at 06:13
  • Indeed. This code will always throw an exception `Non-exhaustive patterns` for all inputs. – AntC Nov 03 '21 at 06:17

3 Answers3

1
> :m Data.List
Data.List> maximum $ map length $ group $ "+++++!!!-------"
7

group :: Eq a => [a] -> [[a]] is in Data.List.

"The group function takes a list and returns a list of lists such that the concatenation of the result is equal to the argument. Moreover, each sublist in the result contains only equal elements. "

map length returns a list with each sublist replaced by its length.

maximum returns the maximum of those lengths.

How did I find group? I searched Hoogle for a function with that signature.

AntC
  • 2,623
  • 1
  • 13
  • 20
  • BTW, `maximum` throws an exception if your input string is empty, because there's no maximum of an empty list. You could fix that with `maximum $ (0:) $ ...` so it returns zero in that case. – AntC Nov 03 '21 at 05:58
  • hoggling for `[Char] -> [[Char]]` or `String -> [String]` doesn't bring anything immediately useful, though. so maybe comment on the generalization... not even `[a] -> [[a]]` works. – Will Ness Nov 03 '21 at 06:07
  • *hoogling ______ – Will Ness Nov 03 '21 at 06:20
0

This isn't clean but it works.

longestChain :: String -> Int
longestChain [] = 0
longestChain xs = go xs 0 1 where
  go [] curr res = res
  go [x] curr res
    | curr > 0  = max (curr+1) res
    | otherwise = res
  go (x:y:xs) curr res
    | x == y = go (y:xs) (curr+1) (max (curr+1) res)
    | curr > 0 = go (y:xs) 0 (max (curr+1) res)
    | otherwise = go (y:xs) 0 res

It isn't enough to add one to the result of the function when we find similar characters. We need to calculate every chain in the string and return the longest length that we find. That's what curr and res take care of.

Also, when you find 2 characters matching, you need to add the second one to your list to match it with the next, otherwise you miss one. In addition, when you find a non-match, if you have your curr greater than 0, it means that this character belongs to the end of the previous chain, so you add one.

user1984
  • 5,990
  • 2
  • 13
  • 32
  • This code is hard to follow, because it's mixing up concerns: matching the chains vs counting each one's length vs tracking the longest. For example, I'm pretty sure the branch `go [] curr res = res` never gets called. – AntC Nov 03 '21 at 07:00
  • I fully agree. I really didn't have time to clean this up. A way would be to just calc the length of the chains in one function and then looking for the highest length in another, which would be similar to your approach with `group`. – user1984 Nov 03 '21 at 07:36
0

More in the style of @user1984's answer. I'd still say this code is hard to read/is muddling concerns.

longestChain :: String -> Int
longestChain xs = go xs 0  where
  go []       curr = curr
  go [x]      curr = curr+1
  go (x:y:xs) curr | x == y    = go (y:xs) (curr+1)
                   | otherwise = max (curr+1) (go (y:xs) 0)

(Here the branch go [] curr = ... is needed, because longestChain might have passed an empty string to go.)

curr is always counting 'in arrears', so if go gets to a singleton [x] at the end of the string, that must have been the last Char of the current chain, increment the length.

If go finds adjacent same Chars x == y, add 1 for the x, recurse on the tail.

If go finds adjacent different chars otherwise, still add 1 for the x (it was the last Char of the current chain); start a new count for the tail. Return the max of the incremented curr cp the max from the tail.

Tests:

Main> longestChain ""
0
Main> longestChain "a"
1
Main> longestChain "Mississippi"
2
Main> longestChain "+++++!!!-------"
7
Main> longestChain "+++++!!!-------*"
7
AntC
  • 2,623
  • 1
  • 13
  • 20