2015-06-19 1 views
2

Я пытаюсь сделать Gender реализовать класс Show.Разрешение неявного для экземпляра Typeclass `Show`

scala> trait Gender extends Show[Gender] 
defined trait Gender 

scala> case object Male extends Gender 
defined object Male 

scala> case object Female extends Gender 
defined object Female 

Далее я определил функцию, которая вызывает show на неявном Show[A].

scala> def f[A : Show](x: A): String = implicitly[Show[A]].shows(x) 
f: [A](x: A)(implicit evidence$1: scalaz.Show[A])String 

Наконец, я создал неявный класс для Show[Gender]:

scala> implicit class GenderShows(g: Gender) extends Show[Gender] { 
    | g match { 
    |  case Male => "Male" 
    |  case Female => "Female" 
    | } 
    | } 
defined class GenderShows 

Я попробовал это, но это не найдя такой неявный:

scala> val male: Gender = Male 
male: Gender = Male 

scala> f(male) 
<console>:20: error: could not find implicit value for 
    evidence parameter of type scalaz.Show[Gender] 
       f(male) 
      ^

ответ

3

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

import scalaz._, Scalaz._ 

trait Gender 
case object Male extends Gender 
case object Female extends Gender 

implicit val GenderShows: Show[Gender] = Show.shows { 
    case Male => "Male" 
    case Female => "Female" 
} 

def f[A: Show](x: A): String = implicitly[Show[A]].shows(x) 

А потом:

scala> val male: Gender = Male 
male: Gender = Male 

scala> f(male) 
res0: String = Male 

Это один из самых больших преимуществ типа классы по подтипированию - они отделяют определение ваших типов данных от определения операций, которые вы хотите поддерживать на этих типах (никто не хочет менять свою иерархию наследования каждый раз, когда им требуется поддержка новой библиотеки сериализации, например).

+0

Спасибо, Трэвис. И 'Show' в' Shows.show' является [объектом] (http://docs.typelevel.org/api/scalaz/nightly/index.html#scalaz.Show$), а не 'trait', I видеть. Является ли этот подход, то есть с использованием определения 'Show # shows'' Show [Gender] ', идиоматического способа определения' Show [A] '? –

+0

'Show.shows' - ​​удобный метод, который позволяет вам создать экземпляр' Show' для 'A' из функции' A => String'. Вы также можете использовать 'new Show [A] {...}' -это просто немного более подробный и менее идиоматический. –

+1

Если вы определяете неявный val внутри объекта сопутствующего пола, тогда компилятор всегда найдет его, даже если он явно не импортирован. – Daenyth