Scala 3. Реализация зависимого типа функции

Изучаю Скала 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
  }
}

Спасибо

Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
0
71
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

В качестве обходного пути вы можете попробовать типы соответствия

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

Shapeless3 и аннотации

Как заставить тип соответствия работать правильно в 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

Дмитрий, большое спасибо за очередное разъяснение. Я немного удивлен, что они сделали это таким сложным, а не автоматическим выводом. Кажется, что Name однозначно указывает на String тип k.Value... версия с summonFrom очень интересна

Max 18.02.2023 16:40

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

anqit 18.02.2023 17:37

@Max Смотрите обновление с параметром типа Value

Dmytro Mitin 18.02.2023 18:06

я вижу, как пример с summonFrom наиболее близок к работе с простым зависимым типом fn type DB = (k: Key) => Option[k.Value]. object Name extends Key[String] похоже на старый стиль с использованием дженериков вместо вложенного типа

Max 18.02.2023 18:19

@Max кажется старым стилем с использованием дженериков вместо вложенного типа. На самом деле они разные stackoverflow.com/questions/59148665/…

Dmytro Mitin 18.02.2023 18:33

Другие вопросы по теме