Scala PartialFunctions от конкретных
Есть ли быстрый способ использовать в качестве конкретной функции (типа, скажем, (A) => B
) как PartialFunction[A, B]
? Самый краткий синтаксис, который я знаю:
(a: A) => a match { case obj => func(obj) }
Есть ли неявное преобразование где-нибудь, что-то вроде:
implicit def funcAsPartial[A, B](func: A => B) = new PartialFunction[A, B] {
def isDefinedAt(a: A) = true
def apply(a: A) = func(a)
}
Наверное, я только что написал то, что искал, но существует ли это уже в библиотеках Scala?
2 ответа
Делать это с неявным преобразованием опасно по той же причине, что (A) => B
не должен наследовать от PartialFunction[A, B]
, То есть контракт PartialFunction гарантирует, что вы можете безопасно * позвонить apply
где бы isDefinedAt
возвращается true
, Контракт Function1 не предоставляет такой гарантии.
Ваше неявное преобразование приведет к PartialFunction, которая нарушает его контракт, если вы примените его к функции, которая не определена повсеместно. Вместо этого используйте сутенера, чтобы сделать преобразование явным:
implicit def funcAsPartial[A, B](f: A => B) = new {
/** only use if `f` is defined everywhere */
def asPartial(): PartialFunction[A, B] = {
case a => f(a)
}
def asPartial(isDefinedAt: A => Boolean): PartialFunction[A, B] = {
case a if isDefinedAt(a) => f(a)
}
}
// now you can write
val f = (i: Int) => i * i
val p = f.asPartial // defined on all integers
val p2 = f.asPartial(_ > 0) // defined only on positive integers
* Как обсуждалось в комментариях, может быть не совсем понятно, что означает здесь "безопасность". Я думаю об этом, что PartialFunction явно объявляет свой домен в следующем точном смысле: если isDefinedAt
возвращает true для значения x
, затем apply(x)
может быть оценена способом, который согласуется с намерением автора функции. Это не значит, что apply(x)
не будет выбрасывать исключение, но просто, чтобы исключение было частью дизайна функции (и должно быть задокументировано).
Нет, я пытался найти один несколько месяцев назад и в итоге написал свой, который по сути такой же, как и ваш.