简体   繁体   中英

How to write a map statement to compare each elements of two lists in haskell?

I have two functions both of which return a list:

enter earth = head $ do
  lst <- earth
  return $ map (\x -> if (x == 0) then 2 else x) lst

helper earth = head $ do
  lst <- tail (earth)
  return lst

where earth is another function that returns a list of lists like [[1,2,3],[2,3,4],[4,7,3]]. In the helper function, I am returning the second element of this list of lists, ie, the head of the tail. And in the enter function, only the head. Now I am writing another function and I want to pass these two functions as arguments to it. I'm doing this:

see :: [Int] -> [Int] -> [Int]
see enter helper = return $ map (\ x y -> if (x == 2) && (y == 0) then 2 else y) enter helper

I'm basically trying to do is to check if the list returned by enter has a 2 and the second list has a zero at that location, then change that 0 to 2 otherwise let the element in the second list be as it is.

What am I doing wrong here?

EDIT:

So, there is an earth function returning like this: [[0,0,1],[1,0,1],[0,0,0]]. The enter function, takes the head of earth(which is [0,0,1] and makes it like this: [2,2,1]. The helper function takes and returns the second element (the head of the tail) of the list of lists returned by earth (which is [1,0,1]). Now the see function, takes these [2,2,1] and [1,0,1] as two arguments, and if an element is 2 in the first list and 0 in the second list (ie, from this example, the second element in both lists, then that 0 should become 2 in the second list, and what should be returned should be something like this: [1,2,1]

zipWith is the function that you're looking for. map only works on one list at a time, so your usage of it will result in a type error. If you just replace map with zipWith in that last line, it should work. Also, you should remove the return . In the context of a list, return only puts something into a singleton list: return x = [x] . Note that return is a function and is not really related to the return in C-influenced languages. I would also suggest not using do notation for lists at this point.

Also, the last function isn't using the other two functions, even though it uses those names. I'm not sure if this is what you want or not though. It is equivalent to a definition of see where you used the names x and y instead of enter and helper .

Here's an example of the behavior of zipWith :

λ> zipWith (*) [2, 3, 4] [10, 100, 1000]
[20,300,4000]

It looks like you want something like this:

       xs = [ ...,     1,     2,     0,     1, ... ]
       ys = [ ...,     3,     0,     4,     0, ... ]
zip xs ys = [ ..., (1,3), (2,0), (0,4), (1,0), ... ]
   result = [ ...,     3,     2,     4,     0, ... ]

result is the list ys with the zeros replaced with 2s where there is a 2 in the list xs .

So you can express this logic pretty much directly as a list comprehension:

result = [ r | (x,y) <- zip xs ys, let r = if y == 0 && x == 2 then 2 else y ]

map only walks over 1 list, but you try to walk over 2 lists at the same time, and calculate something.

So you need a function which takes a function with 2 parameters, 2 lists and returns a list with the same type of the result of the function: (a -> b -> c) -> [a] -> [b] -> [c]

And hoogle finds a function which has this property: zipWith

So you write a helper function which does what you want:

helper 0 2 = 2
helper _ y = y

now you write the see function and put the helper function in a where clause (you probably don't need that function later):

see a b = zipWith helper a b
    where helper 2 0 = 2
          helper _ y = y

I don't know why you use do but this is not necessary here.

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