dreamPr
dreamPr

Reputation: 331

Haskell recursion in lists

I have code like this:

appd (a:e) ((c,b):bs) | a == c && bs /= [] = b:appd(a:e) bs
                      | a /= c && bs /= [] = appd (a:e) bs
                      | a /= c && bs == [] = appd e ((c,b):bs)
                      | otherwise          = b:appd e ((c,b):bs)

It loops throught two lists like [1,2,3] and [(1,2),(6,5),(3,5)] and takes first element of first list and compares it to first element of each tuple in other list, if they are equal then save second element of this tuple. It works fine, but comparison does not work if I take second element of first list, in this case 2.

For example if I have lists like [1,2,3] and [(1,2),(6,5),(3,5)], then function takes 1 from first list and compares to 1, then to 6, then to 3, that works but it does not take second element of first list - 2 and does not do the comparison again. Whats wrong?

Upvotes: 0

Views: 131

Answers (1)

Erik Kaplun
Erik Kaplun

Reputation: 38247

First of all, let me note that you should have included the error message you were getting. You should also have shown us some sample output and sample input.


Anyway: your current appd doesn't handle empty lists, so you need to start by adding cases for that:

appd _     []          = []
appd []    bs          = snd <$> bs  -- you can decide to use [] instead
appd (a:e) ((c,b):bs)
  | a == c && bs /= [] = b:appd(a:e) bs
  | a /= c && bs /= [] = appd (a:e) bs
  | a /= c && bs == [] = appd e ((c,b):bs)
  | otherwise          = b:appd e ((c,b):bs)

now your function works on the input you've provided, but I'm not sure it returns the results you desire:

*Main> appd [1,2,3] [(1,2),(6,5),(3,5)]
[2,5,5]

Furthermore, I've cleaned up your code a little bit and annotated your function with an explicit type signature:

appd :: (Eq a, Eq b) => [a] -> [(a,b)] -> [b]
appd []         bs      = snd <$> bs
appd _          []      = []
appd as@(a:ass) bs@((c,b):bss)
  | a == c && bss /= [] = b : appd as  bss
  | a /= c && bss /= [] =     appd as  bss
  | a /= c && bss == [] =     appd ass bs
  | otherwise           = b : appd ass bs

Also, you can use a much simpler, non-recursive implementation to get the same results as above:

appd :: (Eq a, Eq b) => [a] -> [(a,b)] -> [b]
appd as bs = snd <$> filter (\(a,_) -> a `elem` as) bs

or if you like point free (a.k.a. tacit):

appd :: (Eq a, Eq b) => [a] -> [(a,b)] -> [b]
appd as = (snd <$>) . filter ((`elem` as) . fst)

Note: <$> is an alias for fmap, which in turn behaves exactly like map when used on lists.

Upvotes: 1

Related Questions