-1

I have this code:

import Data.Char
foo  :: String -> String
foo (x:xs) = if (digitToInt(x)) == 0 
                     then foo xs
                     else if (digitToInt(x)) /= 0   
                          then replicate (digitToInt(x)) (head $ take 1 xs) ++ foo (tail xs )
                     else ""    

input: foo "4a5b"

output: "aaaabbbbb"

this line if (digitToInt(x)) == 0 checks if the number is 0 if so then it will expand with the rest of the string:

Example:

input: foo "00004a5b"

output: "aaaabbbbb"

and I added else if (digitToInt(x)) /= 0 to check for the other cases.

However it gives me:

*Main> foo "4a5b"
"aaaabbbbb*** Exception: test.hs:(89,1)-(93,28): Non-exhaustive patterns in function foo

error. Which cases did I miss here?

Will Ness
  • 70,110
  • 9
  • 98
  • 181
nEYncI
  • 3
  • 2
  • 5
    You haven't included a case for the empty string – Robin Zigmond Oct 30 '18 at 17:58
  • You need to incorporate the ending criteria in the foo function. For example, for when you consume the entire tail of the list. It would also be useful to add when you only have one element. – racherb Oct 30 '18 at 18:03
  • Also, single element list case need to be handled. – karakfa Oct 30 '18 at 18:16
  • 2
    @karakfa I'm very far from a Haskell expert, but I'm sure that's not the case. `x:xs` covers all non-empty lists. If it is a singleton list, `x` is that one element and `xs` is the empty list. – Robin Zigmond Oct 30 '18 at 18:24
  • 2
    Test with odd number of elements, `tail xs` will fail with empty list error. Perhaps your input is sanitized already but what if it's not. – karakfa Oct 30 '18 at 18:30
  • Oh good point, I hadn't seen the `tail xs` – Robin Zigmond Oct 30 '18 at 18:33
  • Caution, the case "00004a5b10c" may not work as expected. Could you specify what output you expect to get for that input? – racherb Oct 30 '18 at 19:26

1 Answers1

0

Non-exhaustive patterns in function foo

This error occurs at runtime because the function has not been declared according to the pattern given in the evaluation. This particular case does not consider the end of the tail of a list.

The solution that I present below is an intention to generalize the use case presented.

Note the definition of the function reproduce.

reproduce []        .. --Empty list
reproduce (x:[])    .. --A single value in the list
reproduce (x:y:[])  .. --A list with only two elements x and y
reproduce (x:y:xs)  .. --A list with the first two elements x and y and the rest of the list xs

Here is a solution to the problem presented considering a generalization of the foo function.

The code:

--We import the functions to use
import Data.List (replicate, group, groupBy, all)
import Data.Char (isDigit)

--Grouping by digits
gbDigit :: String -> [String]
gbDigit = groupBy (\x y -> (isDigit x) && (isDigit y)) --ETA reduce form

--Grouping by nor digits
gbNoDigit :: String -> [String]
gbNoDigit s = fmap concat $ groupBy (\x y -> not (all isDigit x) && not (all isDigit y)) (gbDigit s)

--Prepare applying grouping 
--by digit first and not by digit afterwards, therefore:
prepare = gbNoDigit

foo :: String -> String
foo x = concat $ reproduce (prepare x)

reproduce :: [String] -> [String]
reproduce [] = []        --Empty list, nothing to do
reproduce (x:[]) = []    --A numerical value and nothing to replicate, nothing to do
reproduce (x:y:[]) = (replicate (read x::Int)) y --A numeric value and a string to replicate, so we replicate
reproduce (x:y:xs) = (replicate (read x::Int)) y <> reproduce xs --A numeric value, a string to replicate, and a tail to continue

Step by step:

  • Given an entry "003aA3b4vX10z"
  • Group by Digits: ["003","a","A","3","b","4","v","X","10","z"]
  • Group by NoDigits: ["003","aA","3","b","4","vX","10","z"]
  • Reproduce & Concat: "aAaAaAbbbvXvXvXvXzzzzzzzzzz"

Test cases:

Prelude> foo "00004a5b"
Prelude> "aaaabbbbb"

Prelude> foo "4a"
Prelude> "aaaa"

Prelude> foo "4a10B"
Prelude> "aaaaBBBBBBBBBB"

Prelude> foo "3w1.1w6o1l4y1.1com"
Prelude> "www.woooooolyyyy.com"
racherb
  • 335
  • 1
  • 10