2015-11-24 3 views
1

Я хотел бы иметь функциюПодъемное функция `→ б → 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-арных функций)

Например: если бы я не был t сетка результатов, но только список результатов, я мог бы написать f <$> xs <*> ys, что кратким образом, использует заранее определенные комбинаторы и обобщает на n-арные функции очевидным образом. Есть ли аналогичный лаконичный способ написания моего комбинатора?

ответ

7

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

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

TestCase:

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

luv it, perfect: D – Netwave

+0

Это работает, конечно , но это довольно немного подробней, чем то, что я имел в виду. Как я уже сказал, я надеялся на что-то простое в форме, подобной 'f <$> xs <*> ys'. Кроме того, это решение не обобщает на произвольные пересечения, не так ли? –

+3

ИМО - идеальная читаемость ** огромный плюс ** для обобщения/точечного в этом случае – Carsten

4

Кроме того, это решение не обобщающих произвольным traversables, не так ли?

Это делает (и даже больше): оба списочные можно заменить 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 
+0

Любое 'Traversable' является' Functor'. Таким образом, это решение обобщается на произвольный «Traversable». – svenningsson

+0

Я не могу заставить это ввести проверку. ghci присваивает этот тип: 'foo :: (Functor f, Functor f1) => (a -> a1 -> b) -> f a -> f (f1 a1 -> f1 b)'. Любая попытка присвоить желаемый тип приводит к ошибке, частью которой является следующий «Ожидаемый тип: fa -> gb -> f (gc) Фактический тип: fa -> f (gb -> gc)' –

+1

@MichaelWelch К сожалению, Прости. Пришлось полностью переписать его. –