#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 Для меня это неявное выглядит нормально.