Control.Arrow
does not pay much attention to higher-arity functions. What you really want is a function foo :: (a -> a' -> a'') -> (b -> b' -> b'') -> (a,b) -> (a',b') -> (a'',b'')
, the analogue of (***)
for functions of arity 2. There is such a function in Data.Biapplicative (from the package bifunctor), which has the somewhat more general signature biliftA2 :: Biapplicative w => (a -> b -> c) -> (d -> e -> f) -> w a d -> w b e -> w c f
. Since there is a Biapplicative instance for two-element tuples, that is all you need.
The only complaint I can see against your code as it stands is that it the currying of the lambda is non-obvious; I might prefer the more explicit \(a,b) (a',b') -> (lfn a a', rfn b b')
.
Edit notes: I had concluded that the needed function did not exist, and suggested defining it; spurred by Carl's comment, I found the one in Biapplicative (the more general type signature had prevented Hoogle from finding it under my suggested signature).