简体   繁体   中英

Comparing a List of tuples in haskell

Ok, I'm extremely new to Haskell as in I started learning this morning, and have been tasked with taking 2 lists of tuples [("s",1)..] and returning true if they have all the same elements otherwise return false. So far I'm thinking of taking the first element from list one and comparing it to all the elements in list 2 and do that for all the elements and then return true or false. I don't know how to keep track of all the booleans, its easy for if there is a false

|head list1 =/ elementList2 = False

but i'm just confusing my self, so far i have, I have already defined List

listCheck :: List->List -> Bool
listCheck (h1:t1) (h1:t1)
    | h1 == [] = True
    | fst (head h1) /= fst (head h2) = False
    | snd (head h1) /= snd (head h2) = False
    | otherwise = listCheck (t1) (t2)

Any suggestions? The lists can be in any order, so [("a",1),("b",1)] and [("b",1),("a",1)] are equal. the order of the lists can't be changed.

I think it is reasonable to take the head of the list and create an equality function using it. The use any or all from the List library to compare with the tail.

As this is a college exercise I guess you don't want the answer given to you ;-)

listCheck l1 l2 = sort l1 == sort l2

will work fine if list elements are totally ordered, which they will be in the usual case of Strings, numbers etc (and naturally tuples of such elements).

If your elements don't have an ordering things get a lot more difficult, but I don't think you'll encounter that situation often.

The way I always recommend newcomers approach this problem is this:

  1. Look for ways to solve the problem by using standard library functions.
  2. When you've succeeded at that, write your own version of every library functions you used.

In this case, your description of what you're thinking can be finessed into a #1-style solution. Let's quote it:

So far I'm thinking of taking the first element from list one and comparing it to all the elements in list 2 and do that for all the elements and then return true or false.

Here, instead of thinking of doing that just with the first element, picture doing the same thing to all the elements as one step to the solution. There's a standard function that captures this pattern:

-- The `map` function applies the function given as the first argument
-- to all of the elements of the second argument.  The result is a list
-- of all the individual results.
--
-- Example:
--
-- >>> map (+10) [1, 2, 3, 4]
-- [11, 12, 13, 14]
map :: (a -> b) -> [a] -> [b]

So if you can write a function that tests for one value whether it exists in the second list, you can use map to apply that function to all elements of the first list:

step1 :: Eq a => [a] -> [a] -> [Bool]
step1 xs ys = map checkOne xs
  where checkOne x = _fillInTheBlank

(The _fillInTheBlank bit is called a "hole"—you're supposed to actually write the correct code in there!)

The second step would be to check the [Bool] to see whether all of the elements are True . You return True if they are, and False if at least one is false. There is a standard function for that as well:

-- Returns `False` if any element of the list is `False`, `True` otherwise.
and :: [Bool] -> Bool

And now:

listCheck :: Eq a => [a] -> [a] -> Bool
listCheck xs ys = and (map checkOne xs)
  where checkOne x = _fillInTheBlank

map :: (a -> b) -> [a] -> [b]
-- Write your own version of `map`


and :: [Bool] -> Bool
-- Write your own version of `and`

Note what I've done: I've split the problem into smaller parts, each of which I can solve with functions like map and and that will be useful in many other cases. That's what you should be shooting for.

If your goal is to compare the nth element of each list, you are quite close already. The only problem is that you are pattern-matching to pull the two lists apart into head/tail, and then acting as if you hadn't, calling head and tail again:

listCheck :: (Eq a, Eq b) => [(a,b)] -> [(a,b)] -> Bool
listCheck xs ys
    | xs == [] = True
    | fst (head xs) /= fst (head ys) = False
    | snd (head xs) /= snd (head ys) = False
    | otherwise = listCheck (tail xs) (tail ys)

This is far from the most elegant way of doing things, but it is the closest I could find to what you seemed to be trying to write.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM