【问题标题】:Inverse function in ScalaScala中的反函数
【发布时间】:2016-11-05 02:12:57
【问题描述】:

有没有办法在 Scala 中表达任何函数的逆?

例如,如果我有这样的函数f

(x: Int) => x + 1

我希望能够编写一个反函数g,例如:

(f(x): Int) => x // not a valid scala syntax

(x: Int) => inverse(f(x)) // inverse would return (x => x -1)

你知道在 Scala 中做这种事情的方法吗?

注意:x => x+1 仅用于示例。我正在寻找解决此类任务的通用方法。

【问题讨论】:

  • 这个练习不需要反向函数,想想存在的数学定义: Map(S,f) = b |存在 c€S,f(c)=b。
  • 如何创建自己的 InvertibleFunction[Int,Int]

标签: function scala inverse


【解决方案1】:

不,这样的事情是不可能的。问题是并非所有的 mathematical 函数都有逆函数。来自inverse functions 上的维基百科条目:

并非所有函数都有逆函数。要适用此规则,每个元素 y ∈ Y 必须对应不超过一个 x ∈ X;具有此属性的函数 ƒ 称为一对一、信息保留或注入。

例如,平方根 (sqrt) 函数仅在 x >= 0 时是平方函数 (x^2) 的逆函数,其中平方根函数是一对一的。我们可以说,当x < 0 时,平方根函数的负数是平方函数的逆,只是因为x^2 = (-x)^2。但这是平方函数的一个特殊性质,一般情况下肯定不是真的。

【讨论】:

  • 谢谢,我怕那是不可能的,现在已经确定了:)
  • 补充说明,严格可逆的函数称为Bijections
  • 可以计算一些双射函数in Haskell的逆,所以在Scala中也可以。
【解决方案2】:

根据您的使用场景,您可以通过维护来自(Function, Result) => Arguments 的映射来完成此操作,然后调用诸如inverse(f, r) 之类的方法,该方法返回存储在映射中的参数。但是,这仅适用于 1)如果在需要反向值之前调用原始函数,以及 2)如果原始函数是单射的(正如 ddk 已经指出的那样)。

还涉及相当多的实现开销(例如,您可能需要将Function1 映射到Function22 的专用映射),特别是如果您想减少强加给函数实现者的样板代码量。 Aspect-oriented programming 可以在这里提供帮助,类似于 EJB3's Interceptors 的注释也可能有效。

不过,看起来使用场景必须是一个非常特殊的场景,才能证明您必须跳过所有的障碍。

【讨论】:

    【解决方案3】:

    你不能表达一个函数的逆,但你可以表达它的结果的逆,也许这会适合你。

    这在您传递函数时很有用。

    例如,如果您有一个函数 f: Int => Boolean 用作高阶函数中的参数,则可以将其包装在另一个相同类型的函数 x => !f(x) 中,该函数只返回计算的倒数结果:

    def select(ls: List[String], p: String => Boolean): List[String] =
      ls.remove(x => !p(x))
    // select: (ls: List[String], p: String => Boolean)List[String]
    
    val li = List("one", "two", "three")
    // li: List[java.lang.String] = List(one, two, three)
    
    /* using select with some conditions */
    select(li, _.length() > 3)  // equivalent to select(li, x => x.length() > 3)
    // res0: List[String] = List(three)
    select(li, _.length() <= 3) // equivalent to select(li, x => x.length() <= 3)
    // res1: List[String] = List(one, two)
    
    /* using remove with the same conditions */
    li.remove(_.length() > 3)  // equivalent to li.remove(x => x.length() > 3)
    // res2: List[java.lang.String] = List(one, two)
    li.remove(_.length() <= 3)  // equivalent to li.remove(x => x.length() <= 3)
    // res3: List[java.lang.String] = List(three)
    

    注意:List 类中的方法 remove 已被弃用,而应使用 filterNot,但我认为在此示例中 remove 读起来更好。

    【讨论】:

      【解决方案4】:

      从实用主义的角度来看,unapply 方法可以用来表示反函数:

      object f {
        def apply(x: Int) = x + 1
        def unapply(x: Int) = Some(x - 1);
      }
      
      val x = 1
      val f(y) = f(x)
      
      assert(x == y)
      

      【讨论】:

        【解决方案5】:

        我正在添加一个答案,因为 another question 被标记为这个答案的副本,但似乎还没有人提到这一点:理论上可以自动在无限的二进制数字序列上计算函数的“逆”(在某种意义上,它对输入执行详尽的搜索,如果在有限时间内没有解决方案,则回答“无”):参见文章@987654322 @(虽然它使用 Haskell,而不是 Scala)。

        当然,

        实用这种详尽搜索的实用性是另一回事。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2010-11-06
          • 1970-01-01
          • 2017-12-23
          • 2020-08-17
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多