In pure functional languages, is there an algorithm to get the inverse function?
In pure functional languages like Haskell, is there an algorithm to get the inverse of a function, (edit) when it is bijective? And is there a specific way to program your function so it is?
Solution 1:
In some cases, yes! There's a beautiful paper called Bidirectionalization for Free! which discusses a few cases -- when your function is sufficiently polymorphic -- where it is possible, completely automatically to derive an inverse function. (It also discusses what makes the problem hard when the functions are not polymorphic.)
What you get out in the case your function is invertible is the inverse (with a spurious input); in other cases, you get a function which tries to "merge" an old input value and a new output value.
Solution 2:
No, it's not possible in general.
Proof: consider bijective functions of type
type F = [Bit] -> [Bit]
with
data Bit = B0 | B1
Assume we have an inverter inv :: F -> F
such that inv f . f ≡ id
. Say we have tested it for the function f = id
, by confirming that
inv f (repeat B0) -> (B0 : ls)
Since this first B0
in the output must have come after some finite time, we have an upper bound n
on both the depth to which inv
had actually evaluated our test input to obtain this result, as well as the number of times it can have called f
. Define now a family of functions
g j (B1 : B0 : ... (n+j times) ... B0 : ls)
= B0 : ... (n+j times) ... B0 : B1 : ls
g j (B0 : ... (n+j times) ... B0 : B1 : ls)
= B1 : B0 : ... (n+j times) ... B0 : ls
g j l = l
Clearly, for all 0<j≤n
, g j
is a bijection, in fact self-inverse. So we should be able to confirm
inv (g j) (replicate (n+j) B0 ++ B1 : repeat B0) -> (B1 : ls)
but to fulfill this, inv (g j)
would have needed to either
- evaluate
g j (B1 : repeat B0)
to a depth ofn+j > n
- evaluate
head $ g j l
for at leastn
different lists matchingreplicate (n+j) B0 ++ B1 : ls
Up to that point, at least one of the g j
is indistinguishable from f
, and since inv f
hadn't done either of these evaluations, inv
could not possibly have told it apart – short of doing some runtime-measurements on its own, which is only possible in the IO Monad
.
⬜
Solution 3:
You can look it up on wikipedia, it's called Reversible Computing.
In general you can't do it though and none of the functional languages have that option. For example:
f :: a -> Int
f _ = 1
This function does not have an inverse.
Solution 4:
Not in most functional languages, but in logic programming or relational programming, most functions you define are in fact not functions but "relations", and these can be used in both directions. See for example prolog or kanren.