Reputation: 147
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, i.e., 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 (i.e., 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]
Upvotes: 0
Views: 1200
Reputation: 10791
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]
Upvotes: 2
Reputation: 15192
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.
Upvotes: 1
Reputation: 52057
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 ]
Upvotes: 1