Search code examples
arrayshaskellparsec

Parsing scheme vectors in haskell using arrays


I'm attempting the Write Yourself a Scheme in 48 Hours tutorial and as someone new to haskell it's pretty difficult. I'm currently working on a problem where I'm supposed to add the ability to parse scheme vectors (section 3.4 exercise 2).

I'm using this data type:

data LispVal = Atom String                  
         | List [LispVal]                   
         | Vector (Array Int LispVal)

To parse, I'm looking for '#(' then trying to parse the vector contents, drop them in a list and convert that list to an array.

I'm trying to use a list parsing function that I already have and am using but it parses scheme lists into the LispVal List above and I'm having a hard time getting that back into a regular list. Or at least that's what I think my problem is.

lispValtoList :: LispVal -> [LispVal]
lispValtoList (List [a]) = [a]

parseVector :: Parser LispVal
parseVector = do string "#("
             vecArray <- parseVectorInternals       
             char ')'
             return $ Vector vecArray

parseVectorInternals :: Parser (Array Int LispVal)
parseVectorInternals = listToArray . lispValtoList . parseList  

listToArray :: [a] -> Array Int a
listToArray xs = listArray (0,l-1) xs
    where l = length xs

and here's the list parser:

parseList :: Parser LispVal
parseList = liftM List $ sepBy parseExpr spaces

Any ideas on how to fix this? Thanks, Simon

-edit- Here's the compilation error I get:

Couldn't match expected type a -> LispVal' against inferred typeParser LispVal' In the second argument of (.)' namelyparseList' In the second argument of (.)' namely lispValToList . parseList' In the expression: listToArray . lispValToList . parseList


Solution

  • You do not provide lispValtoList but I suppose that it have the following type

    lispValtoList :: LispVal -> [LispVal]
    

    This would suggest the compiler to think that parseList is of type a -> LispVal. But it is not since it is Parser LispVal and so something like P String -> [(LispVal,String)].

    You have to extract the LispVal value that was parsed before putting it in a list. So parseVectorInternals must probably look like

    parseVectorInternals = do parsedList <- parseList 
                              let listOfLispVal = lispValtoList parsedList
                              return $ listToArray listOfLispVal
    

    You could write something more compact, but this code tries to be self-documented ;)