Определение типа частичной функции Scala

val even: PartialFunction[Int, String] = PartialFunction[Int, String] {
  case i if i % 2 == 0 => i + " is even"
}

val isEven: PartialFunction[Int, String] = {
  case i if i % 2 == 0 => i + " is even"
}

val odd: PartialFunction[Int, String] = PartialFunction[Int, String] {
  case x if x % 2 == 1 => x + " is odd"
}


val isOdd: PartialFunction[Int, String] = {
  case x if x % 2 == 1 => x + " is odd"
}

val tot = even orElse odd
val tot2 = isEven orElse isOdd

println(tot(3))
println(tot2(3))

В этом коде tot функция выдает ошибку tot2 функция работает как положено. Единственная разница между ними заключается в том, как они определены. Кто-нибудь может объяснить, почему такая разница в результате?

Заранее спасибо!!!

2 ответа

В основе различие заключается в том, что isDefinedAt в частичной функции не определяется, как можно было бы ожидать в версии с использованием метода PartialFunction.apply. Именно поэтому этот метод теперь устарел, PartialFunction.apply предназначен для преобразования полной функции в частичную функцию с isDefinedAt, всегда возвращающей true, что означает, что он будет думать, что она определена для 3 в вашем примере, и попытаться применить функцию вместо того, чтобы вернуться к четной функции, которую вы предоставили в качестве альтернативы.

Это поднимает общую больную точку в сообществе относительно полных функций против частичных функций. PartialFunction является подтипом Function, я предполагаю, что в смысле разработки ОО это функция с дополнительным методом (isDefinedAt), который сообщает вам, определена ли функция для определенного значения. Многие считают это ошибкой, так как в смысле Лискова, Function должна быть подтипом PartialFunction, потому что вы можете использовать функцию везде, где ожидается PartialFunction, но если вы используете PartialFunction там, где ожидается функция, она скомпилируется, то может произойти сбой во время выполнения. Мне кажется, это потому, что Function может иметь неявный isDefinedAt, который всегда возвращает true, что позволит вам исправить отношение и сделать Function подтипом PartialFunction. Это происходит в PartialFunction.apply, которая ожидает итоговую функцию и из-за этого ожидания определяет, что isDefinedAt всегда возвращает true, но не может обеспечить это ожидание, поэтому, если вы вызываете PartialFunction.apply (somePartialFunction), происходят плохие вещи, которые программисты не ожидают.

PartialFunction.apply Scaladoc

PartialFunction[Int, String]{...} is syntactic sugar for
PartialFunction[Int, String].apply({...})

Чтобы минимизировать:

val even: PartialFunction[Int, String] = PartialFunction[Int, String]{
  case i if i % 2 == 0 => i + " is even"
}

val isEven: PartialFunction[Int, String] = {
  case i if i % 2 == 0 => i + " is even"
}

println(even.isDefinedAt(3)) //true
println(isEven.isDefinedAt(3)) //false

В первых двух случаях вы звоните apply функция в объекте-компаньоне PartialFunction, Я знаю, это звучит так, как будто это должно работать. Но это не потому, что PartialFunction.apply должен прочесть PartialFunction.fromTotalFunction,

Это проблема языка скала, и, если я правильно помню (не могу найти билет в данный момент, посмотрю позже), это apply функция исчезнет и будет заменена fromTotalFunction в Scala 2.13.

ОБНОВИТЬ

Я имел в виду билет № 6005

Кажется, что PartialFunction.apply уже устарела с версии Scala 2.12.5.

Другие вопросы по тегам