Scala 3. 实现依赖函数类型

问题描述 投票:0回答:1

学习 Scala 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
  }
}

谢谢

scala types pattern-matching scala-3 path-dependent-type
1个回答
2
投票

作为解决方法,您可以尝试匹配类型

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 将元组映射到元组类型的未来和返回

Scala 3:类型元组压缩

在 vanilla Scala 3 中表达任意元数的函数

Shapeless3 和注释

如何让匹配类型在 Scala 3 中正常工作

Another option is type classes

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

没有。 (Scala 3.2.2)

Aleksander Boruch-Gruszecki。 Dotty 中的 GADT https://www.youtube.com/watch?v=VV9lPg3fNl8

戴尔维南德。用于模式匹配的空间引擎https://www.youtube.com/watch?v=yaxJPIsy4Js

© www.soinside.com 2019 - 2024. All rights reserved.