Reputation: 461
i am a beginner in haskell programming and very often i get the error
xxx.hs:30:1: parse error on input `xxx'
And often there is a little bit playing with the format the solution. Its the same code and it looks the same, but after playing around, the error is gone.
At the moment I've got the error
LookupAll.hs:30:1: parse error on input `lookupAll'
After that code:
lookupOne :: Int -> [(Int,a)] -> [a]
lookupOne _ [] = []
lookupOne x list =
if fst(head list) == x then snd(head list) : []
lookupOne x (tail list)
-- | Given a list of keys and a list of pairs of key and value
-- 'lookupAll' looks up the list of associated values for each key
-- and concatenates the results.
lookupAll :: [Int] -> [(Int,a)] -> [a]
lookupAll [] _ = []
lookupAll _ [] = []
lookupAll xs list = lookupOne h list ++ lookupAll t list
where
h = head xs
t = tail xs
But I have done everything right in my opinion. There are no tabs or something like that. Always 4 spaces. Is there a general solutoin for this problems? I am using notepad++ at the moment.
Thanks!
Upvotes: 0
Views: 114
Reputation: 297
I think @bheklilr is right - you're missing an else
.
You could fix this particular formatting problem, however, by forming lookupOne
as a function composition, rather than writing your own new recursive function.
For example, you can get the right kind of behaviour by defining lookupOne
like this:
lookupOne a = map snd . filter ((==) a . fst)
This way it's clearer that you're first filtering out the elements of the input list for which the first element of the tuple matches the key, and then extracting just the second element of each tuple.
Upvotes: 1
Reputation: 54068
The problem is not with lookupAll
, it's actually with the previous two lines of code
if fst (head list) == x then snd (head list) : []
lookupOne x (tail list)
You haven't included an else
on this if statement. My guess is that you meant
if fst (head list) == x then snd (head list) : []
else lookupOne x (tail list)
Which I personally would prefer to format as
if fst (head list) == x
then snd (head list) : []
else lookupOne x (tail list)
but that's a matter of taste.
If you are wanting to accumulate a list of values that match a condition, there are a few ways. By far the easiest is to use filter
, but you can also use explicit recursion. To use filter
, you could write your function as
lookupOne x list
= map snd -- Return only the values from the assoc list
$ filter (\y -> fst y == x) list -- Find each pair whose first element equals x
If you wanted to use recursion, you could instead write it as
lookupOne _ [] = [] -- The base case pattern
lookupOne x (y:ys) = -- Pattern match with (:), don't have to use head and tail
if fst y == x -- Check if the key and lookup value match
then snd y : lookupOne x ys -- If so, prepend it onto the result of looking up the rest of the list
else lookupOne x ys -- Otherwise, just return the result of looking up the rest of the list
Both of these are equivalent. In fact, you can implement filter
as
filter cond [] = []
filter cond (x:xs) =
if cond x
then x : filter cond xs
else filter cond xs
And map
as
map f [] = []
map f (x:xs) = f x : map f xs
Hopefully you can spot the similarities between filter
and lookupOne
, and with map
consider f == snd
, so you have a merger of the two patterns of map
and filter
in the explicit recursive version of lookupOne
. You could generalize this combined pattern into a higher order function
mapFilter :: (a -> b) -> (a -> Bool) -> [a] -> [b]
mapFilter f cond [] = []
mapFilter f cond (x:xs) =
if cond x
then f x : mapFilter f cond xs
else : mapFilter f cond xs
Which you can use to implement lookupOne
as
lookupOne x list = mapFilter snd (\y -> fst y == x) list
Or more simply
lookupOne x = mapFilter snd ((== x) . fst)
Upvotes: 4