гетерогенное отображение, зависимые типы во время компиляции

#scala #shapeless

#scala #бесформенный

Вопрос:

Попытка использовать этот трюк Майлза Сэйбина для создания функции, которая принимает параметр только из набора предопределенных types .

 val bool =  Boolean
val timestamp = new Timestamp(date.getTime())
val str = "My String"
 

и затем следующее должно пройти во время компиляции

 takeValue(bool)
takeValue(timestamp)
takeValue(str)
 

но

где takeValue должен произойти сбой takeValue(someIntValue) implicit , если for type Int не определен.И этот сбой будет во время компиляции.

 trait MyConv[K] { type V; def convert: AnyRef => V }

def iMakeConv[V0](con: AnyRef => V0) = new MyConv[con.type] {
  override type V = V0
  val convert = con
}

  def takeValue(value:AnyRef)(implicit conv :MyConv[value.type]) : /[Throwable,conv.V] = /.fromTryCatch(conv.convert(value))
 

И затем

 implicit val strAny = iMakeConv((x:Any) => x.toString)
 

Тогда я хотел takeValue(str) бы работать во время компиляции, но takeValue(someIntValue) потерпеть неудачу во время компиляции, поскольку для этого не implicit определено ничего подходящего. В основном хочу ограничить (во время компиляции) тип types takeValue , который может принимать и терпеть неудачу для других.

Конечно, я делаю здесь что-то не так, потому что при вызове

 takeValue("string")
 

он выдает следующее во время компиляции

  could not find implicit value for parameter conv: 
 MyConv[String("string")]
- not enough arguments for method takeValue: (implicit conv: 
 MyConv[String("string")])scalaz./[Throwable,conv.V]. 
 Unspecified value parameter conv.
 

Ответ №1:

Значение .type часто неправильно понимают. Тип value.type — это тип, имеющий только одно значение — value . Даже если value известно String , value.type что это не String так, но конкретно только один String value .

В результате код пытается найти a MyConv[value.type] , которого не существует, даже если есть MyConv[String] доступный.

Вместо этого takeValue используйте параметр типа:

 def takeValue[T](value: T)(implicit conv: MyConv[T]) : /[Throwable, conv.V] = /.fromTryCatch(conv.convert(value))
 

Или, альтернативно, сделайте параметр типа MyConv контравариантным:

 trait MyConv[-K] { type V; def convert: AnyRef => V }
 

Что позволило MyConv[T] бы использовать a, если value.type является подтипом T .

Вам также нужен другой MyConv и iMakeConv :

 trait MyConv[K] { type V; def convert: K => V }

def iMakeConv[K, V0](con: K => V0) = new MyConv[K] {
  override type V = V0
  val convert = con
}
 

Комментарии:

1. Я бы, вероятно, воздержался от использования дисперсии в подобных случаях, но в противном случае 1.

2. @wingedsubmariner : отличный ответ. разве это implicit не должно работать? `неявный val strConv = iMakeConv[Any,String] ((x: Any) => x.toString)` ?

3. @VikasPandya Для меня это неявное выглядит нормально.