[英]Combine a list of lists with a list using a function in Haskell
我希望能夠在輸入列表的每個元素和列表列表中每個子列表的每個元素之間應用一個函數,如下所示:
mapFunc :: (a -> b -> c) -> [[a]] -> [b] -> [[c]]
例如: mapFunc (*) [[1,2,3],[4,5,6]] [1,2,3]
應該給我: [[1,4,9],[4,10,18]]
。
在 Haskell 中是否有特定的方法可以做到這一點?
我知道它可能需要以某種方式將zipWith
和map
結合起來,我一直在嘗試它們,但並沒有真正解決我的問題
我知道它可能需要
zipWith
和map
的組合
你在正確的軌道上。
給定兩個列表xss
和ys
,您想要獲取xss :: [[a]]
每個元素,作為列表xs :: [a]
,並使用f :: a -> b -> c
用ys :: [b]
壓縮它f :: a -> b -> c
。 “每個元素”建議map
(或列表推導式),因此您可以猜測包含“洞”,編譯器將報告以下類型:
mapFunc :: (a -> b -> c) -> [[a]] -> [b] -> [[c]]
mapFunc f xss ys = map (\xs -> _) xss
-- or,
mapFunc f xss ys = [_ | xs <- xss]
在任何一種情況下,這個洞的類型都是[c]
; 編譯器還為我們提供了可能對填補漏洞有用的范圍內事物的列表:
xs :: [a]
ys :: [b]
xss :: [[a]]
f :: a -> b -> c
mapFunc :: (a -> b -> c) -> [[a]] -> [b] -> [[c]]
然后zipWith
的類型應該清楚如何填充這個洞,即如何通過組合范圍內的值來構造類型為[c]
的值:
zipWith :: (a -> b -> c) -> [a] -> [b] -> [c]
作為練習,您還可以手動內聯map
和zipWith
的定義,以了解如何使用手動遞歸來編寫它。 這里一個有用的擴展是{-# LANGUAGE ScopedTypeVariables #-}
,它允許您使用forall
量詞定義類型a
、 b
和c
的范圍,以便您可以將問題分解為局部定義並給出類型簽名對於每個部分,這些類型簽名可以重用相同的類型變量a
, b
和c
。 從這個簽名開始自己嘗試:
mapFunc :: forall a b c. (a -> b -> c) -> [[a]] -> [b] -> [[c]]
如果你遇到困難,下面有一個關於我將如何構建解決方案的提示。
填空:
mapFunc :: forall ab c. (a -> b -> c) -> [[a]] -> [b] -> [[c]] mapFunc f xss ys = mapping xss where mapping :: [[a]] -> [[c]] mapping (xs : xss') = _ mapping [] = _ zipping :: [a] -> [b] -> [c] zipping (x : xs) (y : ys) = _ zipping [] _ = _ zipping _ [] = _
所以我們必須有
mapFunc (*) [[1,2,3], [4, 5, 6]] [1,2,3]
== [[1,4,9], [4,10,18]]
所以,還有
mapFunc (*) [[1,2,3], [4, 5, 6], [7, 8, 9, 10]] [1,2,3]
== [[1,4,9], [4,10,18], [7, 14, 27] ]
-- and
mapFunc (*) [[1,2,3]] [1,2,3]
== [[1,4,9]]
-- and
mapFunc (*) [[4, 5, 6], [7, 8, 9, 10]] [1,2,3]
== [[4,10,18], [7, 14, 27] ]
因此,
mapFunc (*) ([[1,2,3]] ++ [[4, 5, 6], [7, 8, 9, 10]]) [1,2,3]
== (mapFunc (*)
[[1,2,3]] [1,2,3])
++
(mapFunc (*) [[4, 5, 6], [7, 8, 9, 10]] [1,2,3])
不過,這些具體數字沒有什么特別之處,所以我們必須有
mapFunc (*) ( [xs] ++ xss ) ys =
= (mapFunc (*) [xs] ys ++ mapFunc (*) xss ys)
= ([g xs ys] ++ mapFunc (*) xss ys)
因為正如我們從我們的例子中看到的, (\\xss -> mapFunc (*) xss ys)
是一個保持長度的變換。
那么這個g
函數應該是什么呢?
起泡,沖洗,重復:
我們必須有
g [1,2,3] [1,2,3] == [1,4,9]
g [4,5,6] [1,2,3] == [4,10,18]
g [7,8,9,10] [1,2,3] == [7,14,27]
因此,再次概括為數字本身並沒有什么特別之處,
g xs ys = [ (*) x y | x <- xs | y <- ys ]
就是這樣。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.