Browsed by
Метка: generic

Лирическое отступление

Лирическое отступление

Когда я писал предыдущий пост, я не стал создавать функцию maximum в общем виде, а рассмотрел лишь ее частный случай для List[Int].

Впоследствии я подумал: а почему бы собственно и нет? Тем более что, покопавшись на StackOverflow, я нашел сразу два способа, как это сделать.

В чем проблема

Проблема в том, что мы не можем просто написать общую (generic) функцию:


    def maximum[A](l:List[A]):A = {
      l match { case Nil => throw new Exception("Nil")
        case x::Nil => x
        case x::xs if x > maximum(xs) => x
        case x::xs => maximum(xs)
      }
    }

Компилятор выдаст ошибку:
error: value > is not a member of type parameter A

Наш тип A не имеет метода > !
Очевидно, что наш общий (generic) тип нужно привести к чему-то, что имеет механизм сравнения.
В скале есть 2 трэйта scala.Ordered и scala.math.Ordering, обладающие необходимыми нам методами.

View Bound

Хотя данный способ считается устаревшим (deprecated), он довольно нагляден и понятен:

    
    def maximum[A <% Ordered[A]](l:List[A]):A = {
      l match { case Nil => throw new Exception("Nil")
        case x::Nil => x
        case x::xs if x > maximum(xs) => x
        case x::xs => maximum(xs)
      }
    }

    println(maximum[Char]('f'::'a'::'h'::Nil))

В нашем примере Char не является Ordered, поэтому происходит неявное (implicit) преобразование. Мы как бы заставляем компилятор принимать Char за Ordered.

Context Bounds

При помощи этого подхода можно получить в Scala что-то похожее на type classes из Haskell.


    def maximum[A](l: List[A])(implicit ord: Ordering[A]): A =
      l match {
        case Nil => throw new Exception("maximum of empty list")
        case x :: Nil => x
        case x :: xs => ord.max(x, maximum(xs))
    }

    println(maximum[Char]('f'::'a'::'h'::Nil))

Наша функция принимает неявный (implicit) параметр ord имеющий тип Ordering[A].

Все рабтает. Но возникает вопрос, откуда функция берет этот параметр?

Дело в том, что объект-компаньон Ordering содержит большой набор преобразований для различных типов.