繁体   English   中英

如何检查 function 在 Scala 中是否部分?

[英]How to check if function is partial in Scala?

我有一个接收 function 的方法,但是 function 可能是部分的,在这种情况下我不希望它因 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异常的解决方案

这不是答案,因为我认为 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 正在从该match表达式创建Function而不是PartialFunction ,因此测试失败。 如果您传递了一个真正的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 ...
}

在调用代码中适当。

从 SLS 8.5 的 2.9 起,部分 function 的语法已更改,因此即使您这样做{ case x => y} ,也不意味着它是部分 function。 它的类型将与您定义的完全相同。

在您的情况下,您将其定义为X=>Y (如在您的 function 参数中),所以它只是一个X=>Y (它被编译成常规的 function,不匹配的情况会抛出 MatchError),甚至你做isInstanceOf[PartialFunciton[_,_]] ,它不会匹配。

为了使您的场景工作,您可以简单地将传递的 function 转换为 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

我不确定你作为部分 Function 传递的是什么,但绝对你应该用这样的特定签名来定义它:

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

positive function 仅针对正数定义。 如果是负数,则 function 返回 None 并且您不会在运行时收到 scala.MatchError 。

这个特定的 function 使您能够访问isDefinedAt方法,该方法正在动态测试值是否在 function 的域中。

postive(5).isDefinedAt // 真

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

我在这里演示了为什么在检查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
}

你可以在这里玩它:

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM