首页 文章

isDefinedAt with orElse andThen scala partial function

提问于
浏览
0

我试图理解orElse和andhen是如何工作的但是当与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>

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

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

Question 1 - In following code, the function forOddOnly behaves differently. It doesnt crash for even values but I want it to. Do I need to use 'case' to get this behaviour? I anticipate that the problem could be in implementation of forOddOnly because it works for all 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

this doesn't throw exception scala>(new forOddOnly)(2)res67:Int = 2

打印值小于100工作精细scala> val lessThan100:PartialFunction [Int,Unit] = {case d如果d <100 => 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

Question2 - In following code, I use 'andThen' with forEvenOnly function and lessthan100. The isDefinedAt returns true for even values greater than 100 but passing the value of 100 or more crashes the code. This makes calling isDefinedAt unreliables. Why am I getting this and how to solve it? isDefinedAt works fine for all odd values as expected (and code also crashes is odd value is passed). If I change the implementation of forOddOnly and use 'case', it works but can't I get the same behaviour using 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

problem code. isDefinedAt returns true for even values greater than 100 but code crashes scala> 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)

Question 3 - using andThen with forOddOnly crashes for values more than 99 but not for even values. I guess the there is some common mistake I am making in all these examples

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 回答

  • 1

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

    来自Standard Library scaladoc(重点补充):

    在调用apply之前调用isDefinedAt是调用者的责任,因为如果isDefinedAt为false,则不保证apply会抛出异常以指示错误条件 . 如果未抛出异常,则评估可能会导致任意值 . PartialFunction和scala.Function1之间的主要区别在于PartialFunction的用户可以选择对声明在其域外的输入执行不同的操作 .

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

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

    返回与此部分函数具有相同域的部分函数,该函数将参数x映射到k(this(x)) .

    如果您有 val pfR = pfA andThen pfB ,则 pfR 将与 pfA 具有相同的域 .

相关问题