7

有没有办法表达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仅用于示例。我正在寻找一种通用的方法来解决这种任务。

4

5 回答 5

16

不,这样的事情是不可能的。问题是并非所有数学函数都有逆。从关于反函数的维基百科条目:

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

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

于 2012-09-27T06:25:42.387 回答
2

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

当您传递函数时,这可能很有用。

例如,如果您有一个函数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)

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

于 2012-10-02T18:33:19.233 回答
2

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

还涉及相当多的实现开销(例如,您可能需要一个专用映射Function1to Function22),特别是如果您想减少强加给函数实现者的样板代码量。面向方面的编程在这里可能会有所帮助,类似于EJB3 的拦截器的注释也可能起作用。

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

于 2012-09-27T07:18:40.700 回答
2

从实用主义的角度来看,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)
于 2014-01-08T13:38:12.690 回答
0

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

当然,这种详尽搜索的实际效用是另一回事。

于 2016-07-04T02:50:23.380 回答