isDefinedAt with orElse andThen scala partial functions

时间:2016-11-16 16:54:38

标签: scala

我试图理解orElse和andThen是如何工作的,但是当与orElse和andThen一起使用时,行为'isDefinedAt'是意外的。在我的实现中,isDefinedAt返回true但函数崩溃。这使得实现不可靠。我该如何解决这个问题呢?

我写了以下3个部分功能

PF1

// a function which is defined for even values only. Returns the value
scala> val forEvenOnly:PartialFunction[Int,Int] = {case d if ( (d % 2) == 0) => d}
forEvenOnly: PartialFunction[Int,Int] = <function1>

PF2

// a function which is defined for odd values only. Returns the value
//wanted to try an alternate syntax
scala> class forOddOnly extends PartialFunction[Int,Int] {
     | def apply(x:Int) =  x
     | def isDefinedAt(x:Int) = (x % 2 !=0)
     | }
defined class forOddOnly

PF3

//a function which prints a value if it is less than 100
scala> val lessThan100:PartialFunction[Int,Unit] = {case d if d<100 =>println(d)}
lessThan100: PartialFunction[Int,Unit] = <function1>

单独地,它们看起来很好(除了forOddOnly,它应该会因为偶数值而崩溃但是没有)

scala> val forEvenOnly:PartialFunction[Int,Int] = {case d if ( (d % 2) == 0) => d}
forEvenOnly: PartialFunction[Int,Int] = <function1>

scala> forEvenOnly(1)
scala.MatchError: 1 (of class java.lang.Integer)

scala> forEvenOnly(2)
res60: Int = 2

scala> forEvenOnly.isDefinedAt(1)
res61: Boolean = false

scala> forEvenOnly.isDefinedAt(2)
res62: Boolean = true

问题1 - 在以下代码中,函数forOddOnly的行为有所不同。对于偶数值它不会崩溃,但我希望它。我是否需要使用“案例”才能获得此行为?我预计问题可能在于forOddOnly的实现,因为它适用于所有Int in apply

scala> class forOddOnly extends PartialFunction[Int,Int] {
     | def apply(x:Int) =  x //  I cannot change it to def apply(x:Int) =  if (x % 2 != 0 ) x. This will not compile
     | def isDefinedAt(x:Int) = (x % 2 !=0)
     | }
defined class forOddOnly

scala> (new forOddOnly).isDefinedAt(1)
res64: Boolean = true

scala> (new forOddOnly).isDefinedAt(2)
res65: Boolean = false

scala> (new forOddOnly)(1)
res66: Int = 1

这不会抛出异常     阶&GT; (new forOddOnly)(2)     res67:Int = 2

小于100的打印值工作正常     阶&GT; val lessThan100:PartialFunction [Int,Unit] = {case d if d&lt; 100 =&gt; println(d)}     lessThan100:PartialFunction [Int,Unit] =

scala> lessThan100(1)
1

scala> lessThan100(100)
scala.MatchError: 100 (of class java.lang.Integer)

scala> lessThan100.isDefinedAt(1)
res86: Boolean = true

scala> lessThan100.isDefinedAt(100)
res87: Boolean = false

问题2 - 在下面的代码中,我使用'andThen'和forEvenOnly函数并且使用了lessthan100。对于大于100的偶数值,isDefinedAt返回true,但传递100或更多的值会使代码崩溃。这使得调用isDefinedAt不可靠。为什么我得到这个以及如何解决它? isDefinedAt可以正常工作所有奇数值(并且代码也崩溃是奇数值传递)。如果我更改forOddOnly的实现并使用'case',它可以工作,但我不能使用apply获得相同的行为吗?

scala> val printEvenLessThan100 = forEvenOnly andThen lessThan100
printEvenLessThan100: PartialFunction[Int,Unit] = <function1>

scala> printEvenLessThan100.isDefinedAt(1)
res88: Boolean = false

scala> printEvenLessThan100(1)
scala.MatchError: 1 (of class java.lang.Integer)

scala> printEvenLessThan100.isDefinedAt(2)
res89: Boolean = true

scala> printEvenLessThan100(2)
2

问题代码。对于大于100的偶数值,isDefinedAt返回true但代码崩溃     阶&GT; printEvenLessThan100.isDefinedAt(102)     res94:Boolean = true

scala> printEvenLessThan100(102)
scala.MatchError: 102 (of class java.lang.Integer)

scala> printEvenLessThan100.isDefinedAt(101)
res91: Boolean = false

scala> lessThan100(101)
scala.MatchError: 101 (of class java.lang.Integer)

问题3 - 使用forThen和forOddOnly崩溃的值超过99但不是偶数值。我想我在所有这些例子中都有一些常见的错误

scala> val printOddLessThan100 = (new forOddOnly) andThen lessThan100
printOddLessThan100: PartialFunction[Int,Unit] = <function1>

scala> printOddLessThan100(1)
1

//does not crash
scala> printOddLessThan100(2)
2

scala> printOddLessThan100.isDefinedAt(100)
res102: Boolean = false

scala> printOddLessThan100(100)
scala.MatchError: 100 (of class java.lang.Integer)

scala> printOddLessThan100.isDefinedAt(101)
res97: Boolean = true

scala> printOddLessThan100(101)
scala.MatchError: 101 (of class java.lang.Integer)

当我使用orElse和andThen

组合所有函数时,会发生同样的情况
scala> val printIntLessThan100 = forEvenOnly orElse (new forOddOnly) andThen lessThan100
printIntLessThan100: PartialFunction[Int,Unit] = <function1>

scala> printIntLessThan100(1)
1

scala> printIntLessThan100(2)
2

//why does this return true when the code actually crashes
scala> printIntLessThan100.isDefinedAt(101)
res83: Boolean = true

scala> printIntLessThan100(101)
scala.MatchError: 100 (of class java.lang.Integer)

1 个答案:

答案 0 :(得分:1)

我认为这解决了问题1和问题3。

来自Standard Library scaladoc(强调添加):

  

来电者有责任之前致电isDefinedAt   调用apply,因为如果isDefinedAt为false,则无法保证   apply将抛出异常以指示错误情况。如果   如果不抛出异常,评估可能会导致任意值。

     

PartialFunction和scala.Function1之间的主要区别是   PartialFunction 的用户可以选择来执行某些操作   与声明在其域外的输入不同。

因此,在调用具有未定义的传递参数的PF时,不需要运行时异常。如果没有为该输入定义PF,则结果根本没有定义。

问题2的答案也可以在andThen()的描述中的同一页上找到:

  

返回一个与相同域的部分函数作为此部分函数,​​它将参数x映射到k(this(x))。

如果您有val pfR = pfA andThen pfB,那么pfR将与pfA具有相同的域。