在我的代码中,
zipWith7
运行良好,但现在zipWith7
中的函数需要额外的参数。
zipWith8 (\a b c d e f g h-> ....) List-A ... List-H
而haskell基础库仅支持最多7个版本。
有没有办法可以将功能拓展到N个喜欢的
zipWithN
?
实现此目的的一种简单方法(并不是说
zipWith8
和朋友真的很常见!)是使用 ZipList 类型和 Applicative
运算符。
zipWith8 f a b c d e f g h = getZipList $
f <$> ZipList a
<*> ZipList b
<*> ZipList c
<*> ZipList d
<*> ZipList e
<*> ZipList f
<*> ZipList g
<*> ZipList h
我相信如果你愿意的话,你可以从中弄清楚写
zipWith9
等。
旁白:这在《Learn You a Haskell》处理应用程序的章节中提到过:
除了
之外,标准库还具有zipWith
、zipWith3
等函数,一直到 7 个。zipWith4
接受一个带有两个参数的函数,并用它压缩两个列表。zipWith
采用一个带有三个参数的函数并用它压缩三个列表,依此类推。通过使用具有应用风格的 zip 列表,我们不必为要压缩在一起的每个列表提供单独的 zip 函数。我们只是使用应用风格将任意数量的列表与函数压缩在一起,这非常酷。zipWith3
您可以
zip
前两个列表将数量减一,如果您还 uncurry
该函数:
zipWithNplus1 f xs1 xs2 xs3 ... xsNplus1 =
zipWithN (uncurry f) (zip xs1 xs2) xs3 ... xsNplus1
否则,启用
ParallelListComp
并编写任意数量的并行列表理解:
[ f x1 ... xN
| x1 <- xs1
| x2 <- xs2
| x3 <- xs3
...
| xN <- xsN
]
我一直在努力实现同样的事情。这是我想出的第一个解决方案,似乎有效。
zipWithN :: ([a] -> b) -> [[a]] -> [b]
zipWithN f = go where
go [] = []
go lists | any null lists = []
| otherwise =
let heads = map head lists
in f heads : go (map tail lists)
实际上,它将列表的长度截断为长度相等,然后转置它们,并将 f 应用于它们。
zipWithN product [[1,2],[2,4],[3,6,3490]]
那么 [6, 48]
。
我认为必须有一种比使用
null
、head
和 tail
(这些部分函数)更好的方法。基于 this other stackoverflow post,我想出了以下内容:
zipWithN :: ([a] -> b) -> [[a]] -> [b]
zipWithN f xs = map f (getZipList (sequenceA (map ZipList xs)))
或者,用更多的中间变量名来写:
zipWithN :: ([a] -> b) -> [[a]] -> [b]
zipWithN f xs =
let zipLists = map ZipList xs
truncatedTransposedZLs = sequenceA zipLists
in map f (getZipList truncatedTransposedZLs)
请注意,
ZipList
位于Control.Applicative
中。