Indeed, parsers passed to the select statement must be of the same type. You can specify the type of select statement:
(<|>) :: GenParser tok st a -> GenParser tok st a -> GenParser tok st a
This suggests that he will gladly combine the two parsers if their types of tokens, types of states and types of results are the same.
So, how do we make sure that the parsers you are trying to combine have the same type of result? Well, you already have a Variable data type that captures various forms of variables that may appear in Lua, so we need not return String , [String] or [[String]] , but just Variable s.
But when we try, we are faced with a problem. We cannot allow nestList , etc. Return Variable , but since Variable constructors require variable names, we donβt know them yet. There are workarounds for this (for example, returning the String -> Variable function, which still expects this variable name), but there is a better solution: to separate the variable name from the different types of values ββthat the variable may have.
data Variable = Variable String Value deriving Show data Value = LuaString String | LuaList [Value] deriving (Show)
Note that I removed the NestedLuaList constructor. I modified LuaList to accept a list of Value , not String s, so now the nested list can be expressed as LuaList from LuaList s. This allows lists to be nested arbitrarily deep, and not just two levels, as in your example. I don't know if this is allowed in Lua, but it made writing parsers easier. :-)
Now we can leave lList and nestList return Value s:
lList :: GenParser Char st Value lList = do ss <- between (string "{") (string "}") (sepBy varContent (string ",")) return (LuaList (map LuaString ss)) nestList :: GenParser Char st Value nestList = do vs <- between (string "{") (string "}") (sepBy lList (string ",")) return (LuaList vs)
And varName , which I renamed Variable here, now returns Variable :
variable :: GenParser Char st Variable variable = do vName <- (many letter) eq <- string " = " vCon <- try nestList <|> try lList <|> (do v <- varContent; return (LuaString v)) return (Variable vName vCon)
I think you will find that when you start your parser at some input there are still some problems, but you are already much closer to the solution than before.
Hope this helps!