1

我想要一个功能

foo :: (a → b → c) → [a] → [b] → [[c]]

它接受一个函数f :: a → b → c和两个列表xsys并返回一个网格(即列表列表),其中包含f应用于 和 的每个值组合的xsys

示例:foo [1..3] [4..6]应该返回

[[f 1 4,f 1 5,f 1 6],
 [f 2 4,f 2 5,f 2 6],
 [f 3 4,f 3 5,f 3 6]]

我目前的做法是

foo = traverse . flip . traverse . flip

这可行,但我想知道是否有其他方法或预定义的组合器可以更好地完成(或者甚至可以组合,以便它可以轻松地扩展到三元或 n 元函数)

例如:如果我不想要结果网格而只想要结果列表,我可以编写f <$> xs <*> ys简洁的 ,使用预定义的组合子,并以明显的方式泛化到 n 元函数。是否有类似简洁的方式来编写我的组合器?

4

2 回答 2

7

这是列表推导的工作!

foo f xs ys = [ [ f x y | y <- ys ] | x <- xs]

测试用例:

foo (\x y -> show x ++ " " ++ show y) [1..3] [4..6]

产量:

[["1 4","1 5","1 6"],["2 4","2 5","2 6"],["3 4","3 5","3 6"]
于 2015-11-24T11:47:20.113 回答
4

此外,这个解决方案不能推广到任意可遍历,不是吗?

它确实(甚至更多):两个列表推导都可以替换为fmap, 产生

foo :: (Functor f, Functor g) => (a -> b -> c) -> f a -> g b -> f (g c)
foo f xs ys = fmap (\x -> fmap (\y -> f x y) ys) xs

现在,一些简化:

\y -> f x y === f x
fmap (f x) ys === flip fmap ys (f x) === flip fmap ys . f $ x
\x -> flip fmap ys . f $ x === flip fmap ys . f

所以

foo f xs ys = fmap (flip fmap ys . f) xs
于 2015-11-24T12:29:25.960 回答