2013-10-05 54 views
1

我有一個函數,我想用幾組輸入進行測試。比方說,功能通過兩個輸入列表映射函數

f :: a -> b -> c 

現在我已經投入兩個列表:

inputA :: [a] 
inputB :: [[b]] 

對於inputA !! i,我想在inputB !! i列表中的每個元素評估f $ input !! i。我知道我需要map的幾個應用程序來做到這一點,但我很難解決問題。

我最近一次嘗試是

map f inputA <$> inputB 

它提供了以下錯誤:

Couldn't match expected type a0 -> b0' with actual type [b1]'
In the return type of a call of map'
Probable cause:
map' is applied to too many arguments
In the first argument of (<$>)', namely map f inputA'
In the expression: map f inputA inputB

我應該如何去解決這個問題呢?我不一定需要一個完整的解決方案。一個有益的方向推(甚至推)肯定會被讚賞。

更多的想法:

map f inputA :: [b -> c] 

我認爲這是正確的方向。現在我需要將每個函數映射到inputB的每個輸入列表上。

爲了澄清,我想將i個功能map f inputA超過投入的i個列表inputB映射到得到的結果outputC :: [[c]]

+3

如果你還沒有看到它,你可能也有興趣[快速檢查](http://hackage.haskell.org/package/QuickCheck )。 –

+0

@DanielWagner感謝您的鏈接。我已經很快地閱讀了關於QuickCheck的內容,並且在我關於Haskell的事情清單上。 –

回答

1

如果我正確認識你,是這樣的:

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]] 

如果這是不是你要找什麼,你能提供一個例子輸入和輸出?

編輯

或者這你想要什麼?

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)]] 
+0

這幾乎是我要做的。然而,使用你的例子,我想爲第一個列表中的元素添加1,第二個列表中添加2,第三個列表中添加3,而不是將每個數字都添加到每個列表的所有元素中。 –

+0

@ Code-Guru查看我的更新 – bheklilr

+0

您得到的複選標記是第一個回答。看到你使用'zipWith'後,看起來很明顯(特別是因爲我已經在其他幾個相關的上下文中使用了'zipWith')。 –

1

如果我理解正確的話,這是你所需要的:

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> 

fancyZipMap :: (a -> b -> c) -> [a] -> [[b]] -> [[c]] 
fancyZipMap f xs yys = map (\(x, ys) -> map (f x) ys) $ zip xs yys 
+3

較短的版本:'fancyZipMap f = zipWith $ map。 F' – nponeccop

6

您可以使用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]] 
2

一切很容易與列表理解:

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 

首先nponeccop在評論中所示,以及在在其他的答案暗示最後一個;我們可以通過使用代碼從他們那裏得到它轉換

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 

似乎你試圖找到它的pointfree版本,太:

  = zipWith (map . f) xs yss 
      = (zipWith . (map .)) f xs yss 

所以由ETA還原g = (zipWith . (map .)),但是這可能不是很容易理解。這被進一步混淆爲zipWith <$> (map <$>)甚至zipWith <$> ((<$>) <$>)

或者,我們可以使用the ZipList type from Control.Applicative作爲

  = 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