In pure functional languages, is there an algorithm to get the inverse function?

前端 未结 10 1213
野的像风
野的像风 2020-12-04 06:10

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 f

10条回答
  •  离开以前
    2020-12-04 06:34

    I've recently been dealing with issues like this, and no, I'd say that (a) it's not difficult in many case, but (b) it's not efficient at all.

    Basically, suppose you have f :: a -> b, and that f is indeed a bjiection. You can compute the inverse f' :: b -> a in a really dumb way:

    import Data.List
    
    -- | Class for types whose values are recursively enumerable.
    class Enumerable a where
        -- | Produce the list of all values of type @a@.
        enumerate :: [a]
    
     -- | Note, this is only guaranteed to terminate if @f@ is a bijection!
    invert :: (Enumerable a, Eq b) => (a -> b) -> b -> Maybe a
    invert f b = find (\a -> f a == b) enumerate
    

    If f is a bijection and enumerate truly produces all values of a, then you will eventually hit an a such that f a == b.

    Types that have a Bounded and an Enum instance can be trivially made RecursivelyEnumerable. Pairs of Enumerable types can also be made Enumerable:

    instance (Enumerable a, Enumerable b) => Enumerable (a, b) where
        enumerate = crossWith (,) enumerate enumerate
    
    crossWith :: (a -> b -> c) -> [a] -> [b] -> [c]
    crossWith f _ [] = []
    crossWith f [] _ = []
    crossWith f (x0:xs) (y0:ys) =
        f x0 y0 : interleave (map (f x0) ys) 
                             (interleave (map (flip f y0) xs)
                                         (crossWith f xs ys))
    
    interleave :: [a] -> [a] -> [a]
    interleave xs [] = xs
    interleave [] ys = []
    interleave (x:xs) ys = x : interleave ys xs
    

    Same goes for disjunctions of Enumerable types:

    instance (Enumerable a, Enumerable b) => Enumerable (Either a b) where
        enumerate = enumerateEither enumerate enumerate
    
    enumerateEither :: [a] -> [b] -> [Either a b]
    enumerateEither [] ys = map Right ys
    enumerateEither xs [] = map Left xs
    enumerateEither (x:xs) (y:ys) = Left x : Right y : enumerateEither xs ys
    

    The fact that we can do this both for (,) and Either probably means that we can do it for any algebraic data type.

提交回复
热议问题