My goal was to write a function to parse string of nested parentheses into a corresponding list:
parseParens "()" --> []
parseParens "(())" --> [[]]
parseParens "((()()))" --> [[[],[]]]
First off I discovered that I can't specify easily define a type of the return value. I could do something like:
parseParens :: String -> [[[[t]]]]
But how do I say that it's infinitely nested? I guess Haskell doesn't allow that.
My solution
I came up with my own data type:
data InfiniteList = EmptyList | Cons InfiniteList InfiniteList deriving (Show)
And a parser function that uses this:
parseParens :: String -> InfiniteList
parseParens ('(':xs) =
if remainder == ""
then result
else error "Unbalanced parenthesis"
where (result, remainder) = parseToClose EmptyList xs
parseParens _ = error "Unbalanced parenthesis"
parseToClose :: InfiniteList -> String -> (InfiniteList, String)
parseToClose acc "" = error "Unbalanced parenthesis!"
parseToClose acc (')':xs) = (acc, xs)
parseToClose acc ('(':xs) = parseToClose (concatInfLists acc (Cons result EmptyList)) remainder
where (result, remainder) = parseToClose EmptyList xs
concatInfLists :: InfiniteList -> InfiniteList -> InfiniteList
concatInfLists EmptyList ys = ys
concatInfLists (Cons x xs) ys = Cons x (concatInfLists xs ys)
Working like so:
parseParens "()" --> EmptyList
parseParens "(())" --> Cons EmptyList EmptyList
parseParens "((()()))" --> Cons (Cons EmptyList (Cons EmptyList EmptyList)) EmptyList
How to improve?
There surely must be a better way to do this. Perhaps there's even a way to use the built-in List data type for this?