Взаимозависимые имплициты и их использование с семействами типов

Я пытаюсь создать имитацию семейства типов для использования в шаблоне, где экземпляр класса типов зависит от тип разрешен другим экземпляром класса типов, который представлен в следующем блоке:

( implicit someTypeResolver: SomeTypeResolver[ a ],
           stringRep: StringRep[ someTypeResolver.SomeType ] )

где вы можете видеть, что разрешение stringRep зависит от разрешения someTypeResolver.

Вот полный источник

// A typeclass, 
// which is basically just a type-function from type `a` to `SomeType`
trait SomeTypeResolver[ a ] {
  type SomeType
}
object SomeTypeResolver {
  // An instance, which maps type `Int` to `Boolean`
  implicit val int = new SomeTypeResolver[ Int ]{ type SomeType = Boolean }
  // An instance, which maps type `Char` to `String`
  implicit val char = new SomeTypeResolver[ Char ]{ type SomeType = String }
}

// A simple typeclass which maps a type to some string representation
trait StringRep[ a ] {
  val string: String
}
object StringRep {
  implicit val boolean = new StringRep[ Boolean ]{ val string = "I'm a bool" }
  implicit val char = new StringRep[ Char ]{ val string = "I'm a char" }
}

// Having the following function, which is supposed to return a string 
// representation of a type, which `a` is mapped to
def resolve
  [ a ]
  ( implicit someTypeResolver: SomeTypeResolver[ a ],
             stringRep: StringRep[ someTypeResolver.SomeType ] )
  = stringRep.string

// I expect it to behave like so
assert( resolve[ Int ] == "I'm a bool" )
assert( resolve[ Char ] == "I'm a char" )

Но приведенное выше не удается скомпилировать со следующим сообщением:

недопустимый тип зависимого метода: параметр появляется в типе другого параметра в том же или более раннем разделе

Как к этому подступиться?


person Nikita Volkov    schedule 28.01.2014    source источник


Ответы (1)


Итак, как говорится в ошибке, нам нужно как-то переместить разрешение stringRep в другой отложенный раздел. Для этого мы можем создать промежуточный объект, который вводит этот раздел в свою функцию apply:

def resolve
  [ a ]
  ( implicit someTypeResolver: SomeTypeResolver[ a ] )
  = 
  new {
    def apply( implicit stringRep: StringRep[ someTypeResolver.SomeType ] ) =
      stringRep.string
  }

assert( resolve[ Int ].apply == "I'm a bool" )
assert( resolve[ Char ].apply == "I'm a string" )

Следует отметить, что при таком подходе пользователь должен явно вызвать функцию apply, как показано в утверждениях выше.

person Nikita Volkov    schedule 28.01.2014