It's occasionally useful to consider a slightly richer function definition than
->
, one where you can reason about the preimage of the function's codomain.
One approach is to bundle each ->
with another function describing the preimage:
data Bidirectional p q a b = Bidirectional
{ forwards :: p a b
, backwards :: q b a
}