I'm interested to know if there is a standard library function that does this that I just can't find.
It's easy to miss because of the type class, but look at Control.Arrow
. Plain Arrow
s can't be curried or applied, so the Arrow
combinators are pointfree by necessity. If you specialize them to (->)
, you'll find the one you want is this:
(&&&) :: (Arrow a) => a b c -> a b c' -> a b (c, c')
There are other, similar functions, such as the equivalent operation for Either
, which specialized to (->)
looks like this:
(|||) :: (a -> c) -> (b -> c) -> Either a b -> c
Which is the same as either
.
Out of curiosity, I'd like to rewrite this function in point-free style, but I'm having a lot of trouble with it.
Since you're duplicating an input, you need some way of doing that pointfree--the most common way is via the Applicative
or Monad
instance for (->)
, for example \f g -> (,)
<$> f <*> g
. This is essentially an implicit, inline Reader
monad, and the argument being split up is the "environment" value. Using this approach, join f x
becomes f x x
, pure
or return
become const
, fmap
becomes (.)
, and (<*>)
becomes the S combinator \f g x -> f x (g x)
.