如何检查Scala中的功能是否部分?

时间:2020-04-03 13:37:10

标签: scala partialfunction

我有一个接收函数的方法,但是该函数可能是部分函数,​​在这种情况下,我不希望它因MatchError而失败。

def doSomething[X,Y](opt:Option[X])(f:X=>Y)={
  f match {
    case p:PartialFunction[X,Y]=> opt.flatMap(p.lift) //This doesn't seem to work
    case _ => opt.map(f)
  }
}

这样我就可以使用这样的方法

doSomething(x){
case t if predicate(t) =>  otherMethod(t)
}

所以如果我没有谓词,我可以像这样使用它 此doSomething(x)(otherMethod)而不是

doSoemthing(x){
case t=> otherMethod(t)
}

注意:寻找不需要捕获MatchError异常的解决方案

3 个答案:

答案 0 :(得分:2)

这不是答案,因为我认为您想要的东西在Scala中是不可能的。

原始方法很好,并且可以按预期工作,尽管可能会更简单:

def doSomething[X, Y](opt: Option[X])(f: X => Y): Option[Y] = {
  f match {
    case p: PartialFunction[X, Y] => opt.collect(p)
    case _ => opt.map(f)
  }
}

问题在这里:

doSomething(x){
  case t if predicate(t) =>  otherMethod(t)
}

Scala正在根据该Function表达式创建一个PartialFunction而不是一个match,因此测试失败。如果您通过真实的PartialFunction,则该方法正常。

val p: PartialFunction[Int, Int] = {
  case i: Int if i > 0 => i
}

doSomething(Some(0))(p) // Returns None

我认为没有任何方法可以做您想要的事情,主要是因为doSomething有多个参数列表,这些参数列表混淆了第二个参数列表的类型推导。

我的建议只是使用

x.map(f)

x.collect{
  case ...
}

在调用代码中适当。

答案 1 :(得分:1)

从SLS 8.5的2.9开始,已更改了部分函数的语法,因此即使您执行{ case x => y},也并不意味着它是部分函数。其类型将与您定义的完全相同。

在您的情况下,您将其定义为X=>Y(如在函数参数中一样),因此它只是一个X=>Y(已编译为常规函数,非匹配用例将引发MatchError ),甚至您isInstanceOf[PartialFunciton[_,_]]也不会匹配。

要使您的方案起作用,您只需将传递的函数转换为PartialFunction即可,例如:

doSomething(Some(1))({case 2 => 0}: PartialFunction[Int,Int]) //This returns None without MatchError

同时

doSomething(Some(1)){case 2 => 0} //This gives MatchError and it is not recognized as PartialFunction inside the body

这可能不如您想像的那样方便,但这是使其工作的唯一方法。 (或者您针对这两种情况分别定义2个单独的函数,例如标准库中的collectmap

答案 2 :(得分:-2)

我不确定您要作为部分函数传递什么,但绝对必须使用如下特定签名来定义它:

val positive: PartialFunction[Int, Option[Int]] = {
  case x if x >= 0 => Some(x)
  case _ => None

positive函数仅用于正数。如果为负数,该函数将返回None,并且在运行时不会出现scala.MatchError。

此特定功能使您可以访问isDefinedAt方法,该方法将动态测试值是否在函数的域中。

postive(5).isDefinedAt //是

poistive.isInstanceOf [PartialFunction [Int,Option [Int]]] // true

我在这里说明了为什么您在检查p.isInstanceOf时总是假

def doSomething[X,Y](opt:Option[X])(f:X=>Y)={
  f match {
    case p if p.isInstanceOf[PartialFunction[X,Y]] =>
    println("I'm a pf")
    println(s"Is it PartialFunction: ${p.isInstanceOf[PartialFunction[X,Y]]}")
    opt.map(p)
    case _ =>
    println("I'm not a pf")
    opt.map(f)
  }
}

doSomething[Int, Option[Int]](Some(5))(positive) // partial function case

doSomething[Int, String](Some(5)) { // tricky case
  case s => s.toString
}

您可以here:使用它

相关问题