Есть что-то вроде `map2:: (i → a) → (i → b) → [i] → [(a, b)]`?

Я просто писал такие функции до map4 только потому, что они кажутся полезными:

map2 :: Functor f => (i -> a) -> (i -> b) -> f i -> f (a,b)
map2 f1 f2 = fmap $ \i -> (f1 i, f2 i)

Прежде чем продолжить map8, я подумал, что спрошу, есть ли что-то подобное в каком-то стандартном модуле. Кажется, что Hayoo не знает никакой функции, у которой есть подпись выше.

Примечание. Я уже нашел Control.Arrow.&&&, который сводит приведенное выше к:

map2 f1 f2 = fmap (f1 &&& f2)

Но, похоже, не существует аналогичной функции для разветвления более двух.

Ответы

Ответ 1

(->) i является прикладным функтором, поэтому вы можете написать (&&&) как

f &&& g = (,) <$> f <*> g

и вы можете написать map3 как

map3 f1 f2 f3 = map ((,,) <$> f1 <*> f2 <*> f3)

за исключением того, что он не короче

map3 f1 f2 f3 = map $ \i -> (f1 i, f2 i, f3 i)

Но благодаря подсказке Габриэля это короче:

map3 f1 f2 f3 = map (liftA3 (,,) f1 f2 f3)

Ответ 2

Нет стандартной функции для разветкителя более двух, хотя вы можете имитировать ее с помощью вложенных кортежей:

f :: i -> a
g :: i -> b
h :: i -> c

f &&& g :: i -> (a, b)

(f &&& g) &&& h :: i -> ((a, b), c)

Если вам не нравятся вложенные кортежи, вам нужно будет написать эту функцию самостоятельно:

fanout3 :: (i -> a) -> (i -> b) -> (i -> c) -> i -> (a, b, c)
fanout3 f g h i = (f i, g i, h i)

Как вы упомянули в своем вопросе, как только у вас есть такая функция, вы можете просто map его:

map (fanout3 f g h) :: [i] -> [(a, b, c)]