Scala中的反函数

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中如何做这种事情吗?

N.B: x => x+1 只是一个例子。我正在寻找一种通用的方法来解决这种任务。


8
这个练习不需要反向函数,考虑存在的数学定义:Map(S,f) = b | 存在 c€S,使得 f(c)=b。 - Julien Lafont
你想创建自己的InvertibleFunction[Int,Int]吗? - Edmondo
5个回答

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

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

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

1
谢谢,我担心这是不可能的,现在已经确认了 :) - Loic
1
额外说明一下,严格可逆的函数被称为“双射”。 - christopher
在Haskell中可以计算一些双射函数的反函数,因此在Scala中也可能是可能的。 - Anderson Green

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)

注意:在List类中,方法remove已被弃用,应该使用filterNot代替,但我认为在这个例子中,remove更易懂。


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)

2
根据您的使用场景,您可以通过维护一个从(函数,结果) => 参数的映射来实现这个目标,然后调用一个方法,如inverse(f, r),该方法返回存储在映射中的参数。但是,这仅适用于1)在需要反向值之前调用原始函数,并且2)如果原始函数是单射(正如ddk已经指出的那样)。

还涉及相当多的实现开销(例如,您可能需要一个专用于Function1Function22的地图),特别是如果您想减少对函数实现者施加的样板代码量。面向方面的编程可以在这里发挥作用,类似于EJB3的拦截器的注释也可能起作用。

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


0

我正在添加一个回答,因为另一个问题被标记为此问题的重复,并且似乎没有人提到过这一点:在无限二进制数列上自动计算函数"反函数"(在输入上执行穷举搜索,并在有限时间内回答"无解")理论上是可能的:参见文章"Seemingly impossible functional programs"(虽然它使用了Haskell,而不是Scala)。

当然,这种穷举搜索的实用性是另外一个问题。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接