fuuman
fuuman

Reputation: 461

Haskell - format issue

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

Answers (2)

immutablestate
immutablestate

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

bheklilr
bheklilr

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

Related Questions