Изучаю Скала 3.
как я могу сделать этот код соответствующим типу и скомпилировать?
trait Key {
type Value
}
object Name extends Key {
type Value = String
}
object Age extends Key {
type Value = Int
}
type DB = (k: Key) => Option[k.Value]
val dbImpl: DB = (k: Key) => {
k match {
case Name => Some("abc") // this does not compile, how can i make it sniff Value type is String automatically?
case Age => None
}
}
Спасибо
В качестве обходного пути вы можете попробовать типы соответствия
trait Key
object Name extends Key
object Age extends Key
type OptValue[K <: Key] = K match
case Name.type => Option[String]
case Age.type => Option[Int]
def dbImpl[K <: Key](k: K): OptValue[K] = k match
case _: Name.type => Some("abc")
case _: Age.type => None
или
val dbImpl: [K <: Key] => K => OptValue[K] =
[K <: Key] => (k: K) => k match
case _: Name.type => Some("abc")
case _: Age.type => None
Я напоминаю, что
type DB = [K <: Key] => K => OptValue[K]
val dbImpl: DB = [K <: Key] => (k: K) => k match
case _: Name.type => Some("abc")
case _: Age.type => None
или
def dbImpl[K <: Key](k: K): OptValue[K] = k match
case Name => Some("abc")
case Age => None
или
type Value[K <: Key] = K match
case Name.type => String
case Age.type => Int
def dbImpl[K <: Key](k: K): Option[Value[K]] = k match
case _: Name.type => Some("abc")
case _: Age.type => None
не будет работать.
scala 3 map tuple to futures of tuple и обратно
Scala 3: сжатие типизированных кортежей
Экспресс-функция произвольной арности в vanilla Scala 3
Как заставить тип соответствия работать правильно в Scala 3
Другой вариант — классы шрифтов
trait Key
object Name extends Key
object Age extends Key
// type class
trait KeyValue[K <: Key]:
type Value
type Out = Option[Value]
def apply(k: K): Out
object KeyValue:
type Aux[K <: Key, V] = KeyValue[K] { type Value = V }
def instance[K <: Key, V](f: K => Option[V]): Aux[K, V] = new KeyValue[K]:
override type Value = V
override def apply(k: K): Out = f(k)
given Aux[Name.type, String] = instance(_ => Some("abc"))
given Aux[Age.type, Int] = instance(_ => None)
def dbImpl[K <: Key](k: K)(using kv: KeyValue[K]): kv.Out = kv(k)
Еще один вариант — встраивание и использование scala.compiletime.summonFrom
trait Key:
type Value
object Name extends Key:
override type Value = String
object Age extends Key:
override type Value = Int
inline def dbImpl(k: Key): Option[k.Value] = inline k match
case Name => summonFrom {
case _: (String =:= k.Value) => Some("abc")
}
case Age => summonFrom {
case _: (Option[Int] =:= Option[k.Value]) => None: Option[Int]
}
Проще всего сделать Value
параметром типа, а не членом типа.
trait Key[Value]
object Name extends Key[String]
object Age extends Key[Int]
def dbImpl[V](k: Key[V]): Option[V] = k match
case Name => Some("abc")
case Age => None
Эта реализация компилируется во время
trait Key:
type Value
object Name extends Key:
override type Value = String
object Age extends Key:
override type Value = Int
def dbImpl[V](k: Key {type Value = V}): Option[V] = k match
case Name => Some("abc")
case Age => None
или
trait Key:
type Value
object Key:
type Aux[V] = Key { type Value = V }
object Name extends Key:
override type Value = String
object Age extends Key:
override type Value = Int
def dbImpl[V](k: Key.Aux[V]): Option[V] = k match
case Name => Some("abc")
case Age => None
или
trait Key:
type Value
object Name extends Key:
override type Value = String
object Age extends Key:
override type Value = Int
def dbImpl(k: Key): Option[k.Value] = k match
case Name => Some("abc")
case Age => None
нет. (Скала 3.2.2)
Александр Борух-Грущецкий. GADT в Дотти https://thewikihow.com/video_VV9lPg3fNl8
Дейл Вейнанд. Космический движок для сопоставления с образцом https://thewikihow.com/video_yaxJPIsy4Js
Я должен согласиться с @Max, похоже, что большая часть преимуществ этих функций на уровне типов будет заключаться в том, что компилятор сможет немного больше делать выводы и рассуждать о типах самостоятельно, особенно в том, что кажется красивым такой простой случай, но, возможно, это будет улучшено в будущих версиях.
@Max Смотрите обновление с параметром типа Value
я вижу, как пример с summonFrom
наиболее близок к работе с простым зависимым типом fn type DB = (k: Key) => Option[k.Value]
. object Name extends Key[String]
похоже на старый стиль с использованием дженериков вместо вложенного типа
@Max кажется старым стилем с использованием дженериков вместо вложенного типа. На самом деле они разные stackoverflow.com/questions/59148665/…
Дмитрий, большое спасибо за очередное разъяснение. Я немного удивлен, что они сделали это таким сложным, а не автоматическим выводом. Кажется, что
Name
однозначно указывает наString
типk.Value
... версия сsummonFrom
очень интересна