List binary map. I.e.
liftA2 for lists.
Note: this is not
ZipWith.
>>> :kind! Map2 (Con2 '(,)) [1, 2, 3] ['x', 'y']
Map2 (Con2 '(,)) [1, 2, 3] ['x', 'y'] :: [(Natural, Char)]
= ['(1, 'x'), '(1, 'y'), '(2, 'x'), '(2, 'y'), '(3, 'x'), '(3, 'y')]
This function is a good example to highlight how to defunctionalize
definitions with anonymous functions.
The simple definition can be written using
concatMap and
map from
Prelude:
>>> import Prelude as P (concatMap, map, (.), flip)
>>> let map2 f xs ys = P.concatMap (\x -> P.map (f x) ys) xs
>>> map2 (,) "abc" "xy"
[('a','x'),('a','y'),('b','x'),('b','y'),('c','x'),('c','y')]
However, to make it easier (arguably) to defunctionalize, the
concatMap argument lambda can be written in point-free form
using combinators:
>>> let map2 f xs ys = P.concatMap (P.flip P.map ys P.. f) xs
>>> map2 (,) "abc" "xy"
[('a','x'),('a','y'),('b','x'),('b','y'),('c','x'),('c','y')]
Alternatively, we could define a new "top-level" function
>>> let map2Aux f ys x = P.map (f x) ys
and use it to define @map2:
>>> let map2 f xs ys = P.concatMap (map2Aux f ys) xs
>>> map2 (,) "abc" "xy"
[('a','x'),('a','y'),('b','x'),('b','y'),('c','x'),('c','y')]