2011-07-26 2 views
5

Есть ли какой-либо быстрый способ использования в качестве конкретной функции (типа, скажем, (A) => B) как PartialFunction[A, B]? Наиболее кратким синтаксис я знаю это:Scala PartialFunctions от конкретных

(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?

ответ

5

Выполнение этого с неявным преобразованием опасно по той же причине, что (A) => B не должно наследовать от PartialFunction[A, B]. То есть, контракт PartialFunction гарантирует, что вы можете безопасно * позвонить apply где бы то ни было isDefinedAttrue. В контракте 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) не будет генерировать исключение, а просто исключение было частью дизайна функции (и должно быть документировано).

+0

Спасибо; У меня было неправильное представление о том, что Function1 подразумевается как определяемый по всему домену. –

+0

@AaronNovstrup: ваше объяснение контракта PartialFunction является единственным, что имеет смысл, но не отражено ScalaDocs (по крайней мере до 2.9.1). «ScalaDocs PartialFunction» утверждает, что: «Частичная функция типа« PartialFunction [A, B] »- это унарная функция, в которой домен необязательно включает все значения типа' A'. Более того, они никогда не утверждают, что безопасно (в каком смысле) вызывать f где бы они ни были определены, и это довольно легко нарушить, как это делает литеральный 'PartialFunction'' {case 0 => 1/0} '. Откуда у вас такая информация? Должен ли быть отправлен отчет об ошибке? – Blaisorblade

+0

@Blaisorblade Я считаю, что я прочитал это объяснение в списке рассылки, когда я изучал Scala (это было какое-то время), и я не смотрел ни одну документацию, когда писал этот ответ. И, да, легко и даже довольно часто нарушать этот контракт (например, обернуть/перестроить исключение в блоке catch). Реальная точка заключается в том, что PartialFunctions определяют свой домен, в то время как обычные функции не имеют (с некоторой нечеткостью о том, что это на самом деле означает). –

0

Нет, я попытался найти его несколько месяцев назад и в итоге написал свой собственный, который по сути такой же, как и ваш.

+0

Мне кажется, что '(A) => B' должно наследовать от' PartialFunction [A, B] ', а не наоборот. –

+1

Я бы согласился с тем, что функция (total) является частичной функцией, которая определяется везде (isDefinedAt (x) = true). Мартин Одерски, однако, говорит, что функция не гарантируется как полная функция, просто ее домен недокументирован. Таким образом, PartialFunction - это функция, которая документирует свой домен. –

+0

http://www.scala-lang.org/node/2750 –