问题
I have a function that I want to test with several sets of inputs. Let's say the function is
f :: a -> b -> c
Now I have two lists of inputs:
inputA :: [a]
inputB :: [[b]]
For inputA !! i
, I want evaluate f $ input !! i
for each element of the list at inputB !! i
. I know I need several applications of map
to do this, but I am having difficulty wrapping my head around a solution.
My most recent attempt is
map f inputA <$> inputB
which gives the following error:
Couldn't match expected type
a0 -> b0' with actual type
[b1]'
In the return type of a call ofmap'
map' is applied to too many arguments
Probable cause:
In the first argument of(<$>)', namely
map f inputA'
In the expression: map f inputA inputB
How should I go about solving this problem? I don't necessarily want a complete solution. A push (or even a shove) in a helpful direction would definitely be appreciated.
Additional thoughts:
map f inputA :: [b -> c]
I think this is the right direction. Now I need to map each of the functions over each list of inputs in inputB
.
To clarify, I want to map the i
th function in map f inputA
over the i
th list of inputs in inputB
to get a result outputC :: [[c]]
.
回答1:
If I'm understanding you correctly, something like:
mapNested :: (a -> b -> c) -> [a] -> [[b]] -> [[c]]
mapNested f [] _ = []
mapNested f _ [] = []
mapNested f (x:xs) ys = concatMap (map (f x)) ys : mapNested f xs ys
Main> mapNested (+) [1, 2, 3] [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
[[2,3,4,5,6,7,8,9,10],[3,4,5,6,7,8,9,10,11],[4,5,6,7,8,9,10,11,12]]
If this isn't what you're looking for, could you provide an example input and output?
EDIT
Or is this what you're wanting?
mapNested :: (a -> b -> c) -> [a] -> [[b]] -> [[c]]
mapNested f xs = zipWith map (map f xs)
Main> mapNested (,) [1, 2, 3] [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
[[(1,1),(1,2),(1,3)],[(2,4),(2,5),(2,6)],[(3,7),(3,8),(3,9)]]
回答2:
You can use zipWith
Prelude> let a = [1,2,3]
Prelude> let b = [[1,2,3],[4,5,6],[7,8,9]]
Prelude> zipWith (\a' bl -> map (+a') bl) a b
[[2,3,4],[6,7,8],[10,11,12]]
回答3:
everything is easy with list comprehensions:
g f xs yss = [ [f x y | y <- ys] | (x,ys) <- zip xs yss]
= [ map (f x) ys | (x,ys) <- zip xs yss]
= [ map fx ys | (fx,ys) <- zip (map f xs) yss]
= zipWith map (map f xs) yss
= [ (map . f) x ys | (x,ys) <- zip xs yss]
= zipWith (map . f) xs yss
the last one first shown by nponeccop in the comments, and also hinted at in other answers; we can get it from them by using code transformations
map c $ zip a b == zipWith c a b
map (c a) b == (map . c) a b
\a b-> map (c a) b == map . c
it seems you've tried to find a pointfree version of it, too:
= zipWith (map . f) xs yss
= (zipWith . (map .)) f xs yss
so by eta-reduction g = (zipWith . (map .))
but this might not be easily comprehensible. This is further obfuscated as zipWith <$> (map <$>)
and even zipWith <$> ((<$>) <$>)
.
Or, we can use the ZipList type from Control.Applicative as
= zipWith (map . f) xs yss
= getZipList $ pure (map . f) <*> ZipList xs <*> ZipList yss
= getZipList $ (map . f) <$> ZipList xs <*> ZipList yss
= getZipList $ map <$> (f <$> ZipList xs) <*> ZipList yss
回答4:
If I understand you correctly, this is what you need:
Prelude> let f x y = x + y
Prelude> let xs = [1, 2, 3, 4, 5]
Prelude> let ys = [[1, 2], [3, 4, 5], [6, 7], [8], [9, 10]]
Prelude> map (\(x, ys) -> map (f x) ys) $ zip xs ys
[[2,3],[5,6,7],[9,10],[12],[14,15]]
Prelude>
i.e.
fancyZipMap :: (a -> b -> c) -> [a] -> [[b]] -> [[c]]
fancyZipMap f xs yys = map (\(x, ys) -> map (f x) ys) $ zip xs yys
来源:https://stackoverflow.com/questions/19194396/mapping-a-function-over-two-input-lists