Meowcolm024
Meowcolm024

Reputation: 392

Similar functions applied to nested list in Haskell

Here is the problem I encountered. I have some functions that are similar in their bodies (with a slightly difference), but they have signatures.

flatB :: [[String]] -> [[String]]
flatB []  = []
flatB [x] = [x]
flatB (a : b : xs) | isDigit (head n) = replicate (read n :: Int) a ++ flatB xs
                   | otherwise = a : flatB (b : xs)
    where n = head b

flatC :: [String] -> [String]
flatC []  = []
flatC [x] = [x]
flatC (a : b : xs) | isDigit (head b) = replicate (read b :: Int) a ++ flatC xs
                   | otherwise = a : flatC (b : xs)

I'm expecting the function to do the following:

> flatC ["a","2","b"]
["a","a","b"]

> flatB [["a","b"],["2"]]
[["a","b"],["a","b"]]

The code above works. But I'm wondering whether there is a simpler way to achieve this?

I think that creating a typeclass may be the way, but I don't know how to do it.

Upvotes: 2

Views: 86

Answers (1)

Li-yao Xia
Li-yao Xia

Reputation: 33509

The only difference is how you read the Int out of every other element on the list, which you can factor out as a function parameter:

import Text.Read (readMaybe)

flat :: (a -> Maybe Int) -> [a] -> [a]
flat _ []  = []
flat _ [x] = [x]
flat readElem (a : b : xs)
  | Just n <- readElem b = replicate n a ++ flat readElem xs
  | otherwise = a : flat readElem (b : xs)

flatB :: [[String]] -> [[String]]
flatB = flat readHead
  where
    readHead [] = Nothing
    readHead (n : _) = readMaybe n

flatC :: [String] -> [String]
flatC = flat readMaybe

Upvotes: 3

Related Questions