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 type
Parser LispVal' In the second argument of(.)' namely
parseList' In the second argument of(.)' namely
lispValToList . parseList' In the expression: listToArray . lispValToList . parseList
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 ;)
parseList
is a Monad of type parser LispVal
whereas lispValtoList wants a plain LispVal so:
parseVectorInternals = listToArray . lispValtoList `liftM` parseList
If you are where I was 8 weeks ago reading the same book the following will help you as well:
All these lines are equivalent:
parseVectorInternals = (listToArray . lispValtoList) `liftM` parseList
parseVectorInternals = liftM (listToArray . lispValtoList) parseList
parseVectorInternals = parseList >>= \listLispVal -> return listToArray (lispValtoList listLispVal)
parseVectorInternals = do
listLispVal <- parseList
return listToArray (lispValtoList listLispVal)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With