15

I just wrote functions like this up to map4 just because they seem useful:

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

Before I continue to map8 i thought I'd ask if there is something similar in some standard module. Hayoo doesn't seem to know any function that has the signature above.

Note: I already found Control.Arrow.&&& which reduces the above to:

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

But there doesn't seem to be a similar function for a fanout more than two.

fho
  • 6,787
  • 26
  • 71

2 Answers2

19

(->) i is an applicative functor, so you can write (&&&) as

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

and you could write map3 as

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

except that it isn't shorter than

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

But thanks to Gabriel's tip, this is shorter:

map3 f1 f2 f3 = map (liftA3 (,,) f1 f2 f3)
Sjoerd Visscher
  • 11,840
  • 2
  • 47
  • 59
11

There is no standard function for a fanout more than two, although you can simulate it using nested tuples:

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

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

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

If you don't like nested tuples then you will have to write this function yourself:

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

Like you mentioned in your question, once you have such a function you can then just map it:

map (fanout3 f g h) :: [i] -> [(a, b, c)]
Gabriella Gonzalez
  • 34,863
  • 3
  • 77
  • 135
  • Btw ... is there something like a `Flatten` typeclass that converts things like `(a,(b,c))` to `(a, b, c)` or `[[[a],a],a]` to `[a,a,a]`. I am aware of `concat` but there seem to be a common structure there. – fho Jun 15 '13 at 08:55
  • @Florian There isn't a `Flatten` type class that I'm aware of, but even if there were I would probably avoid it. It would be very difficult to reason about when it would stop flattening or what the final type would be. – Gabriella Gonzalez Jun 15 '13 at 13:54
  • I guess for lists some recursive application of `concat` until the result doesn't change any more would work. (Isn't that what `fix` is about?) – fho Jun 17 '13 at 19:44
  • @Florian `fix` wouldn't work because the type changes after each application of `concat`. However, I would generally avoid doing something like that because it's not very idiomatic Haskell. Also, this requires a lot of type class abuse and results in very confusing compiler errors. – Gabriella Gonzalez Jun 17 '13 at 19:53
  • Yep ... I didn't meant to use it ... this was just out of interest :) – fho Jun 17 '13 at 19:56