Тип стерт при проверке неявных доказательств

Я пытаюсь создать бедную версию реализации уточненных типов с простой проверкой содержимого строки и проверкой возвращаемого типа с помощью Implicit свидетельства другой функции. Кажется, что тип был стерт после того, как он был возвращен из функции check. Может ли кто-нибудь предложить мне трюк scala, чтобы сделать это эффективно?

sealed trait Validate
sealed trait Pass extends Validate
sealed trait Fail extends Validate
type SUCCESS = Pass
case class Validator[State <: Validate: TypeTag](s: String = "") {

  def check = {
    if (s == "awesome") {
      Validator[Pass](s)
    } else {
      Validator[Fail](s)
    }
  }

  def pass: Validator[Pass] = Validator[Pass](s)
  def fail: Validator[Fail] = Validator[Fail](s)

  def validate(implicit ev: State =:= SUCCESS): String = s
  def testResult = typeOf[State] =:= typeOf[SUCCESS]

}

Validator("awesome").check.testResult // true
Validator("awesome").check.validate // Cannot prove that _1 =:= MdocApp.this.SUCCESS.
Стоит ли изучать 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
61
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

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

Если я правильно понял вашу цель, вы хотели бы заменить реализацию с использованием scala-reflectTypeTag (testResult) на реализацию с использованием статических типов и имплицитов (validate).

Тип возвращаемого значения check — это просто Validator[Validate], а не Validator[Pass] или Validator[Fail].

Типы разрешаются во время компиляции, поэтому компилятор должен знать, является ли строка "awesome" во время компиляции. Например, вы можете поднять s, чтобы ввести уровень. Строка с типом String слишком грубая, вместо этого вы можете использовать точные одноэлементные подтипы. Вы можете ввести класс типов для "сопоставления шаблонов" во время компиляции.

// type class
trait Check[S <: String] {
  type State <: Validate
}
trait LowPriorityCheck {
  type Aux[S <: String, State0 <: Validate] = Check[S] {type State = State0 }
  implicit def default[S <: String]: Aux[S, Fail] = null
}
object Check extends LowPriorityCheck {
  implicit val pass: Aux["awesome", Pass] = null
}

case class Validator[S <: String with Singleton, State <: Validate](s: S) {
  def check(implicit check: Check[S]): Validator[S, check.State] =
    Validator[S, check.State](s)

  def validate(implicit ev: State =:= SUCCESS): String = s
}

Validator("awesome").check.validate // awesome

Validator("abc").check.validate //  Cannot prove that Fail =:= SUCCESS

Если вы предпочитаете сохранить обе реализации, вы можете восстановить TypeTag границы контекста. Тогда вам придется сделать метод check универсальным. Лучше сделать State параметром типа класса типа, а не членом типа (иначе будет ошибка «невозможно создать TypeTag ссылку на тип LowPriorityCheck.<refinement>.State, локальный по отношению к reifee: вместо этого используйте WeakTypeTag», но используя WeakTypeTag/weakTypeOf вместо TypeTag/ typeOf слишком прекрасно, weakTypeOf[State] =:= typeOf[SUCCESS] никогда не бывает правдой).

trait Check[S <: String, State <: Validate]
trait LowPriorityCheck {
  implicit def default[S <: String]: Check[S, Fail] = null
}
object Check extends LowPriorityCheck {
  implicit val pass: Check["awesome", Pass] = null
}

case class Validator[S <: String with Singleton, State <: Validate: TypeTag](s: S) {
  def check[St <: Validate : TypeTag](implicit 
    check: Check[S, St]
  ): Validator[S, St] = Validator[S, St](s)
  //def check[St <: Validate : Check[S, *] : TypeTag]: Validator[S, St] = Validator[S, St](s)

  def testResult = typeOf[State] =:= typeOf[SUCCESS]

  def validate(implicit ev: State =:= SUCCESS): String = s
}

Спасибо за ответ. Как вы думаете, возможно ли сделать более динамическую проверку вместо того, чтобы сравнивать с константой «круто» (например, string.length> 5), используя этот подход? Я предполагаю, что нет, поскольку компилятор не сможет сделать это во время компиляции.

Led 01.05.2023 09:11

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