2011-07-26 14 views
5

Czy istnieje jakiś szybki sposób użycia jako konkretnej funkcji (typu, powiedzmy, (A) => B) jako PartialFunction[A, B]? Najbardziej zwięzły składnia znam to:Scala PartialFunctions z konkretnych

(a: A) => a match { case obj => func(obj) } 

Czy istnieje niejawna konwersja wszędzie, coś jak:

implicit def funcAsPartial[A, B](func: A => B) = new PartialFunction[A, B] { 

    def isDefinedAt(a: A) = true 
    def apply(a: A) = func(a) 

} 

Chyba po prostu napisał, co szukałem, ale czy to już istnieje w biblioteki Scala?

Odpowiedz

5

Wykonanie tego z niejawną konwersją jest niebezpieczne, z tego samego powodu, że (A) => B nie powinien dziedziczyć po PartialFunction[A, B]. Oznacza to, że umowa z PartialFunction gwarantuje, że możesz bezpiecznie * zadzwonić pod numer apply wszędzie tam, gdzie isDefinedAt zwraca true. Umowa Function1 nie przewiduje takiej gwarancji.

Twoja niejawna konwersja spowoduje operację częściową, która narusza jej umowę, jeśli zastosujesz ją do funkcji, która nie jest zdefiniowana wszędzie. Zamiast tego należy użyć alfonsa, aby konwersja wyraźne:

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 

* Jak wspomniano w komentarzach, to może nie być do końca jasne, co „bezpieczeństwo” oznacza tutaj. Myślę, że funkcja PartialFunction jawnie deklaruje swoją domenę w następujący sposób: jeśli isDefinedAt zwraca true dla wartości x, wówczas można oszacować apply(x) w sposób zgodny z intencją autora tej funkcji. Ten nie oznacza, że ​​ oznacza, że ​​apply(x) nie wyrzuci wyjątku, a jedynie, że wyjątek był częścią projektu funkcji (i powinien być udokumentowany).

+0

Dziękuję; Miałem błędne przekonanie, że Function1 sugeruje bycie zdefiniowanym w całej domenie. –

+0

@AaronNovstrup: twoje wyjaśnienie umowy PartialFunction jest jedyną, która ma sens, ale nie jest odzwierciedlana przez ScalaDocs (przynajmniej do 2.9.1). ScalaDocs firmy PartialFunction twierdzi, że: "Częściowa funkcja typu' PartialFunction [A, B] 'jest funkcją jednoargumentową, w której domena niekoniecznie zawiera wszystkie wartości typu" A "." Co więcej, nigdy nie twierdzą, że jest bezpiecznie (w jakim sensie) wywoływać f wszędzie tam, gdzie jest to zdefiniowane, i jest to raczej łatwe do złamania, jak to robi literał 'PartialFunction'' {case 0 => 1/0} '. Skąd masz te informacje? Czy należy zgłosić zgłoszenie błędu? – Blaisorblade

+0

@ Blaisorblade Uważam, że przeczytałem to wyjaśnienie na liście mailingowej, gdy uczyłem się Scala (już dawno temu), a ja nie patrzyłem na żadną dokumentację, gdy pisałem tę odpowiedź. I tak, jest łatwe, a nawet dość częste, naruszenie tej umowy (np. Zawinięcie/ponowne zgłoszenie wyjątku w bloku catch). Rzeczywistym punktem jest to, że PartialFunctions definiują swoją domenę, podczas gdy zwykłe Funkcje nie (z pewnym rozmytaniem o tym, co to właściwie oznacza). –

0

Nie, próbowałem go znaleźć kilka miesięcy temu i napisałem własną, która jest w zasadzie taka sama jak twoja.

+0

Wydaje mi się, że '(A) => B' powinien dziedziczyć po' PartialFunction [A, B] ', a nie odwrotnie. –

+1

Zgadzam się z tym, ponieważ (całkowita) funkcja jest funkcją częściową, która jest wszędzie zdefiniowana (isDefinedAt (x) = true). Martin Odersky mówi jednak, że funkcja nie ma gwarancji, że jest funkcją całkowitą, tylko że jej domena jest nieudokumentowana. Tak więc funkcja częściowa jest funkcją, która dokumentuje swoją domenę. –

+0

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

Powiązane problemy