Functional programming 在纯函数语言中,是否有求逆函数的算法?

Functional programming 在纯函数语言中,是否有求逆函数的算法?,functional-programming,Functional Programming,在像Haskell这样的纯函数语言中,当函数是双射函数时,是否有一种算法来求其逆(编辑)?有没有一种特殊的方法来编程你的函数呢?没有,不是所有的函数都有倒数。例如,这个函数的倒数是什么 f x = 1 你可以在维基百科上查到,它叫做 一般来说,您不能这样做,而且没有一种函数式语言有这样的选项。例如: f :: a -> Int f _ = 1 此函数没有逆函数。并非每个函数都有逆函数。如果您将讨论限制在一对一函数上,则反转任意函数的能力将授予破解任何密码系统的能力。我们有点希望这是不可

在像Haskell这样的纯函数语言中,当函数是双射函数时,是否有一种算法来求其逆(编辑)?有没有一种特殊的方法来编程你的函数呢?

没有,不是所有的函数都有倒数。例如,这个函数的倒数是什么

f x = 1

你可以在维基百科上查到,它叫做

一般来说,您不能这样做,而且没有一种函数式语言有这样的选项。例如:

f :: a -> Int
f _ = 1

此函数没有逆函数。

并非每个函数都有逆函数。如果您将讨论限制在一对一函数上,则反转任意函数的能力将授予破解任何密码系统的能力。我们有点希望这是不可行的,即使在理论上

在某些情况下,是的!有一篇漂亮的论文叫做,它讨论了一些情况——当你的函数足够多态时——在这些情况下,完全自动地导出一个反函数是可能的。(本文还讨论了当函数不是多态函数时,是什么使问题变得困难。)


如果你的函数是可逆的,你得到的结果是相反的(带有虚假输入);在其他情况下,您会得到一个函数,该函数尝试“合并”旧输入值和新输出值。

不,通常不可能

证明:考虑类型

的双射函数
type F = [Bit] -> [Bit]

假设我们有一个反相器
inv::F->F
,这样
inv F。F≡ id
。假设我们已经测试了它的函数
f=id
,方法是确认

inv f (repeat B0) -> (B0 : ls)
由于输出中的第一个
B0
一定是在某个有限的时间之后出现的,因此在
inv
实际评估测试输入以获得该结果的深度以及调用
f
的次数上,我们都有一个上限
n
。现在定义一系列函数

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
显然,对于所有
0 n
  • 评估
    head$g j l
    是否至少有
    n
    不同的列表匹配
    replicate(n+j)B0++B1:ls
  • 到目前为止,至少有一个
    gj
    f
    是无法区分的,而且由于
    inv f
    没有做过这两个评估,
    inv
    不可能把它区分开来——除非自己做一些运行时测量,这只有在
    IO Monad
    中才可能


    像这样的任务几乎总是无法确定的。您可以为某些特定函数提供解决方案,但不是一般的解决方案

    在这里,您甚至无法识别哪些函数具有逆函数。引述:

    如果lambda项集既不是空的也不是满的,那么它就不是平凡的。如果A和B是在(beta)相等条件下闭合的两个非平凡、不相交的lambda项集,那么A和B是递归不可分的

    让我们假设A是表示可逆函数的lambda项集,B是其余的。两者都是非空的,在beta等式下闭合。所以不可能决定一个函数是否可逆


    (这适用于非类型lambda演算。当我们知道要反转的函数的类型时,我不知道参数是否可以直接适用于类型lambda演算。但我很确定它会类似。)

    我最近一直在处理类似的问题,不,我想说(a)在很多情况下这并不困难,但是(b)它根本没有效率

    基本上,假设您有
    f::a->b
    ,并且
    f
    确实是一个对象。你可以用一种非常愚蠢的方式计算逆
    f':b->a

    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
    
    如果
    f
    是一个双射,并且
    enumerate
    确实生成
    a
    的所有值,那么您最终将命中
    a
    ,从而
    f a==b

    具有
    有界
    枚举
    实例的类型可以轻松地使
    递归可枚举
    。也可以使成对的
    可枚举
    类型成为
    可枚举

    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
    
    可枚举类型的析取也是如此:

    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
    

    事实上,我们可以对
    (,)
    中的任何一种
    进行此操作,这可能意味着我们可以对任何代数数据类型进行此操作。

    如果您可以枚举函数的域,并可以比较范围中的元素是否相等,您可以-以一种相当简单的方式。我所说的枚举是指有一个所有可用元素的列表。我将坚持使用Haskell,因为我不知道Ocaml(甚至不知道如何正确地利用它;-)

    您要做的是遍历域的元素,看看它们是否等于您尝试反转的范围的元素,然后取第一个有效的元素:

    inv :: Eq b => [a] -> (a -> b) -> (b -> a)
    inv domain f b = head [ a | a <- domain, f a == b ]
    
    以及您喜欢的任意多个常量(您可以说“我知道它们是双射!”),例如:

    notBi :: Bi Bool Bool
    notBi = Bi not not
    
    add1Bi :: Bi Integer Integer
    add1Bi = Bi (+1) (subtract 1)
    
    idBi :: Bi a a 
    idBi = Bi id id
    
    invertBi :: Bi a b -> Bi b a
    invertBi (Bi a i) = (Bi i a)
    
    composeBi :: Bi a b -> Bi b c -> Bi a c
    composeBi (Bi a1 i1) (Bi a2 i2) = Bi (a2 . a1) (i1 . i2)
    
    mapBi :: Bi a b -> Bi [a] [b]
    mapBi (Bi a i) = Bi (map a) (map i)
    
    bruteForceBi :: Eq b => [a] -> (a -> b) -> Bi a b
    bruteForceBi domain f = Bi f (inv domain f)
    
    和一些智能组合器,例如:

    notBi :: Bi Bool Bool
    notBi = Bi not not
    
    add1Bi :: Bi Integer Integer
    add1Bi = Bi (+1) (subtract 1)
    
    idBi :: Bi a a 
    idBi = Bi id id
    
    invertBi :: Bi a b -> Bi b a
    invertBi (Bi a i) = (Bi i a)
    
    composeBi :: Bi a b -> Bi b c -> Bi a c
    composeBi (Bi a1 i1) (Bi a2 i2) = Bi (a2 . a1) (i1 . i2)
    
    mapBi :: Bi a b -> Bi [a] [b]
    mapBi (Bi a i) = Bi (map a) (map i)
    
    bruteForceBi :: Eq b => [a] -> (a -> b) -> Bi a b
    bruteForceBi domain f = Bi f (inv domain f)
    
    我想你可以做
    反转(mapBi add1Bi)[1,5,6]
    得到
    [0,4,5]
    。如果你以一种聪明的方式选择你的组合符,我认为你必须手工编写一个
    Bi
    常量的次数可能会非常有限


    毕竟,如果你知道一个函数是一个双射函数,你很有希望在你的头脑中有一个证明这一事实的草图,Curry Howard同构应该能够将其转化为一个程序:-)

    不是在大多数函数式语言中,而是在逻辑编程或关系式编程中,你定义的大多数函数实际上不是函数,而是函数“关系”,它们可以在两个方向上使用。例如,请参见prolog或kanren。

    在某些情况下,可能
    idBi :: Bi a a 
    idBi = Bi id id
    
    invertBi :: Bi a b -> Bi b a
    invertBi (Bi a i) = (Bi i a)
    
    composeBi :: Bi a b -> Bi b c -> Bi a c
    composeBi (Bi a1 i1) (Bi a2 i2) = Bi (a2 . a1) (i1 . i2)
    
    mapBi :: Bi a b -> Bi [a] [b]
    mapBi (Bi a i) = Bi (map a) (map i)
    
    bruteForceBi :: Eq b => [a] -> (a -> b) -> Bi a b
    bruteForceBi domain f = Bi f (inv domain f)
    
    bijective_function x = x*2+1
    
    main = do
        print $ bijective_function 3
        print $ inverse_function bijective_function (bijective_function 3)
    
    data Expr = X | Const Double |
                Plus Expr Expr | Subtract Expr Expr | Mult Expr Expr | Div Expr Expr |
                Negate Expr | Inverse Expr |
                Exp Expr | Log Expr | Sin Expr | Atanh Expr | Sinh Expr | Acosh Expr | Cosh Expr | Tan Expr | Cos Expr |Asinh Expr|Atan Expr|Acos Expr|Asin Expr|Abs Expr|Signum Expr|Integer
           deriving (Show, Eq)
    
    instance Num Expr where
        (+) = Plus
        (-) = Subtract
        (*) = Mult
        abs = Abs
        signum = Signum
        negate = Negate
        fromInteger a = Const $ fromIntegral a
    
    instance Fractional Expr where
        recip = Inverse
        fromRational a = Const $ realToFrac a
        (/) = Div
    
    instance Floating Expr where
        pi = Const pi
        exp = Exp
        log = Log
        sin = Sin
        atanh = Atanh
        sinh = Sinh
        cosh = Cosh
        acosh = Acosh
        cos = Cos
        tan = Tan
        asin = Asin
        acos = Acos
        atan = Atan
        asinh = Asinh
    
    fromFunction f = f X
    
    toFunction :: Expr -> (Double -> Double)
    toFunction X = \x -> x
    toFunction (Negate a) = \a -> (negate a)
    toFunction (Const a) = const a
    toFunction (Plus a b) = \x -> (toFunction a x) + (toFunction b x)
    toFunction (Subtract a b) = \x -> (toFunction a x) - (toFunction b x)
    toFunction (Mult a b) = \x -> (toFunction a x) * (toFunction b x)
    toFunction (Div a b) = \x -> (toFunction a x) / (toFunction b x)
    
    
    with_function func x = toFunction $ func $ fromFunction x
    
    simplify X = X
    simplify (Div (Const a) (Const b)) = Const (a/b)
    simplify (Mult (Const a) (Const b)) | a == 0 || b == 0 = 0 | otherwise = Const (a*b)
    simplify (Negate (Negate a)) = simplify a
    simplify (Subtract a b) = simplify ( Plus (simplify a) (Negate (simplify b)) )
    simplify (Div a b) | a == b = Const 1.0 | otherwise = simplify (Div (simplify a) (simplify b))
    simplify (Mult a b) = simplify (Mult (simplify a) (simplify b))
    simplify (Const a) = Const a
    simplify (Plus (Const a) (Const b)) = Const (a+b)
    simplify (Plus a (Const b)) = simplify (Plus (Const b) (simplify a))
    simplify (Plus (Mult (Const a) X) (Mult (Const b) X)) = (simplify (Mult (Const (a+b)) X))
    simplify (Plus (Const a) b) = simplify (Plus (simplify b) (Const a))
    simplify (Plus X a) = simplify (Plus (Mult 1 X) (simplify a))
    simplify (Plus a X) = simplify (Plus (Mult 1 X) (simplify a))
    simplify (Plus a b) = (simplify (Plus (simplify a) (simplify b)))
    simplify a = a
    
    inverse X = X
    inverse (Const a) = simplify (Const a)
    inverse (Mult (Const a) (Const b)) = Const (a * b)
    inverse (Mult (Const a) X) = (Div X (Const a))
    inverse (Plus X (Const a)) = (Subtract X (Const a))
    inverse (Negate x) = Negate (inverse x)
    inverse a = inverse (simplify a)
    
    inverse_function x = with_function inverse x