2015-01-29 11 views
5

Shapeless Features Overview ukazuje następujący przykład:Zrozumienie `Monomorphism` Przykład bezkształtne

import poly._ 

// choose is a function from Sets to Options with no type specific cases 
object choose extends (Set ~> Option) { 
    def apply[T](s : Set[T]) = s.headOption 
} 

scala> choose(Set(1, 2, 3)) 
res0: Option[Int] = Some(1) 

scala> choose(Set('a', 'b', 'c')) 
res1: Option[Char] = Some(a) 

Jednak nie wm brakiem doświadczenia bezkształtnym, zrozumienie różnicy między tym i są następujące:

scala> def f[T](set: Set[T]): Option[T] = set.headOption 
f: [T](set: Set[T])Option[T] 

scala> f(Set(1,2,3)) 
res0: Option[Int] = Some(1) 

scala> f(Set('a', 'b', 'c')) 
res1: Option[Char] = Some(a) 

Odpowiedz

7

Ważna różnica polega na tym, że choose to funkcja, którą można przekazać jako wartość. Nie można dokonać (rozsądny) wartość z f, ponieważ Scala nie obsługuje polimorficzne wartości funkcji:

scala> val fun = f _ 
fun: Set[Nothing] => Option[Nothing] = <function1> 

Jak widać, Scala ustala rodzaj elementem Nothing renderowania funkcję bezużyteczny dla niepustych zbiorów:

scala> fun(Set(1)) 
<console>:10: error: type mismatch; 
found : Int(1) 
required: Nothing 
       fun(Set(1)) 
        ^

Działa to tak, jak można by się spodziewać w przypadku podejścia bezkształtnego.

+0

Dzięki za wyjaśnienie. Kolejny przykład w instrukcji "pairApply" również jest dobrym przykładem. Proszę mi powiedzieć, czy "mógłbym" napisać jako funkcję przez 'def'? Ciekawi mnie, dlaczego zastosowano podejście "object ...". –

+0

'choose' można zapisać jako * metodę * na obiekcie, ale nie może to być funkcja * * (a * wartość * typu' Funkcja1'). Zaletą posiadania go jako "obiektu" jest to, że można go przekazać do innej funkcji bez utraty generic: 'def applyToIntsAndStrings (mapper: Set ~> Option): (Option [Int], Option [String]) = (mapper (Set (1, 2), Mapper (Set ("Hello"))))), a następnie możemy wywołać 'applyToIntsAndStrings (choose)'. Nie możesz tego zrobić z ogólnym 'def'. – lmm