Функция подъема `a → b → c` в`[a] → [b] → [[c]]`

Я хотел бы иметь функцию

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

это берет функцию f :: a → b → c и два списка xs а также ys и возвращает сетку (то есть список списков), содержащий значения f применяется к каждой комбинации значений из xs а также ys,

Пример: 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-арные функции очевидным образом. Есть ли такой же краткий способ написания моего комбинатора?

2 ответа

Это работа для понимания списка!

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

Кроме того, это решение не обобщается на произвольные обходные пути?

Это делает (и даже больше): оба понимания списка могут быть заменены 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
Другие вопросы по тегам