gpt4 book ai didi

scala - 如何在 Scala 3/Dotty 中实现像 MapK 这样的类型?

转载 作者:行者123 更新时间:2023-12-04 11:35:23 26 4
gpt4 key购买 nike

我正在尝试但未能让这样的东西在 Scala 3 中工作:

type TupleK[K[*], V[*], A] = (K[A], V[A]) 

final class MapK[K[*], V[*]] private (val rawMap: Map[K[?], V[?]]) {

def foreach(f: TupleK[K, V, ?] => Unit): Unit = {
rawMap.foreach(f.asInstanceOf[Tuple2[K[?], V[?]] => Any])
}
}

object MapK {

def apply[K[*], V[*]](entries: TupleK[K, V, ?]*): MapK[K, V] = {
new MapK[K, V](Map(entries: _*))
}
}
像这样使用:
class Key[A]()

type Id[A] = A

val intKey = Key[Int]
val strKey = Key[String]

MapK[Key, Id](intKey -> 1, strKey -> "a")
在 Scala 2 中,只需要通过替换 * 来调整语法。和 ?_ (当然, _* 除外)。
然而,在 Scala 3 中,基本上每一行都会出错,“无法将更高类型的类型应用到通配符参数”: Scastie .
文档说存在类型是 dropped在 Scala 3 中,但是他们并没有真正给出任何关于如何处理这个问题的重要示例。
文档提到“存在类型与依赖路径的类型在很大程度上重叠”——这个 MapK 可以用依赖路径的类型来实现吗?我已阅读 this但不明白如何应用它,或者在我的情况下是否可行。
而且,如果不是路径依赖类型……那又如何? Scala 似乎不太可能被“简化”到无法再实现此功能的地步,所以我一定遗漏了一些东西。
ETA:除了下面我自己的回答,我还做了 this repo并写道 this article关于在 Scala 3 中编码 MapK 的各种方法。

最佳答案

我能够产生一个有效的,尽管令人难以置信的烦人的实现。 This pointer特别有值(value)。
首先,几点说明:

  • 对此的类型推断在很多层面上都很糟糕。测试中的所有手动类型归属,以及下面的所有隐式转换都是需要的。
  • 显然 Scala 不够聪明,无法弄清楚 Atype Id[A] = A在查找隐式时功能相同,因此需要临时隐式转换的组合爆炸。丑陋且可扩展性不强。
  • 观察 Scala 3 中可用的不同选项:foreach , foreachT , 和 foreachK .它们都有风格上的权衡。
  • 如果您可以改进其中任何一项,请告诉我。这有效,但它在 Scala 2 中要好得多。

  • MapK 实现:
    class MapK[K[_], V[_]] protected(protected val rawMap: Map[Type[K], Type[V]]) {

    def apply[A](key: K[A]): V[A] = {
    rawMap(key).asInstanceOf[V[A]]
    }

    def updated[A](key: K[A], value: V[A]): MapK[K, V] = {
    MapK.unsafeCoerce(rawMap.updated(key, value))
    }

    def updated[A](pair: (K[A], V[A])): MapK[K, V] = {
    MapK.unsafeCoerce(rawMap.updated(pair._1, pair._2))
    }

    def foreach[A](f: ((K[A], V[A])) => Unit): Unit = {
    rawMap.foreach(f.asInstanceOf[(([Type[K], Type[V]])) => Any])
    }

    def foreachT(f: Type.Tuple2[K, V] => Unit): Unit = {
    foreach { (k, v) => f((k, v)) }
    }

    def foreachK(f: [A] => (K[A], V[A]) => Unit): Unit = {
    foreach { (k, v) => f(k, v) }
    }

    }

    object MapK {

    def unsafeCoerce[K[_], V[_]](rawMap: Map[Type[K], Type[V]]): MapK[K, V] = {
    new MapK[K, V](rawMap)
    }

    def apply[K[_], V[_]](entries: Type.Tuple2[K, V]*): MapK[K, V] = {
    new MapK[K, V](Map(entries.asInstanceOf[Seq[(Type[K], Type[V])]]: _*))
    }
    }

    您可能想要实现的 MapK 中的其他方法基本上遵循与 foreach 相同的模式。 , foreachT , 或 foreachK .
    现在,用法:
      def test(caption: String)(code: => Unit): Unit = code

    def assertEquals[A](a: A, b: A): Unit = assert(a == b)

    case class Key[A](label: String, default: A)

    val boolKey = Key[Boolean]("bool", false)

    val intKey = Key[Int]("int", 0)

    val strKey = Key[String]("str", "")

    val optionMap = MapK[Key, Option](boolKey -> Some(true), intKey -> Some(1), strKey -> Option("a"), strKey -> None)

    val idMap = MapK[Key, Id](boolKey -> true, intKey -> 1, strKey -> "hello")

    val expectedOptionValues = List[Type.Tuple3[Key, Option, Id]](
    (boolKey, Some(true), false),
    (intKey, Some(1), 0),
    (strKey, None, "")
    )

    val expectedIdValues = List[Type.Tuple3[Key, Id, Id]](
    (boolKey, true, false),
    (intKey, 1, 0),
    (strKey, "hello", "")
    )

    test("optionMap - apply & updated") {
    assertEquals(optionMap(intKey), Some(1))
    assertEquals(optionMap(strKey), None)
    assertEquals(optionMap.updated(strKey, Some("yo"))(strKey), Some("yo"))
    }

    test("optionMap - foreach") {
    var values: List[Type.Tuple3[Key, Option, Id]] = Nil

    optionMap.foreach { (k, v) =>
    values = values :+ (k, v, k.default)
    }

    assertEquals(values, expectedOptionValues)
    }

    test("optionMap - foreachT") {
    var values: List[Type.Tuple3[Key, Option, Id]] = Nil

    optionMap.foreachT { pair => // no parameter untupling :(
    values = values :+ (pair._1, pair._2, pair._1.default)
    }

    assertEquals(values, expectedOptionValues)
    }

    test("optionMap - foreachK") {
    var values: List[Type.Tuple3[Key, Option, Id]] = Nil

    optionMap.foreachK {
    [A] => (k: Key[A], v: Option[A]) => // need explicit types :(
    values = values :+ (k, v, k.default)
    }

    assertEquals(values, expectedOptionValues)
    }

    test("idMap - apply & updated") {
    assertEquals(idMap(intKey), 1)
    assertEquals(idMap(strKey), "hello")
    assertEquals(idMap.updated(strKey, "yo")(strKey), "yo")
    }

    test("idMap - foreach") {
    var values: List[Type.Tuple3[Key, Id, Id]] = Nil

    idMap.foreach { (k, v) =>
    values = values :+ (k, v, k.default)
    }

    assertEquals(values, expectedIdValues)
    }

    test("idMap - foreachT") {
    var values: List[Type.Tuple3[Key, Id, Id]] = Nil

    idMap.foreachT { pair =>
    values = values :+ (pair._1, pair._2, pair._1.default)
    }

    assertEquals(values, expectedIdValues)
    }

    test("idMap - foreachK") {
    var values: List[Type.Tuple3[Key, Id, Id]] = Nil

    idMap.foreachK {
    [A] => (k: Key[A], v: A) =>
    values = values :+ (k, v, k.default)
    }

    assertEquals(values, expectedIdValues)
    }
    现在,使这项工作发挥作用的支持 Actor :
    import scala.language.implicitConversions // old style, but whatever

    type Id[A] = A

    type Type[F[_]] <: (Any { type T })


    object Type {

    type Tuple2[F[_], G[_]] <: (Any { type T })

    type Tuple3[F[_], G[_], H[_]] <: (Any { type T })
    }


    implicit def wrap[F[_], A](value: F[A]): Type[F] =
    value.asInstanceOf[Type[F]]

    implicit def wrapT2[F[_], G[_], A](value: (F[A], G[A])): Type.Tuple2[F, G] =
    value.asInstanceOf[Type.Tuple2[F, G]]

    implicit def wrapT2_P1[F[_], A](t: (F[A], A)): Type.Tuple2[F, Id] = wrapT2[F, Id, A](t)

    implicit def wrapT3[F[_], G[_], H[_], A](value: (F[A], G[A], H[A])): Type.Tuple3[F, G, H] =
    value.asInstanceOf[Type.Tuple3[F, G, H]]

    implicit def wrapT3_P1[F[_], G[_], A](value: (F[A], A, A)): Type.Tuple3[F, Id, Id] =
    value.asInstanceOf[Type.Tuple3[F, Id, Id]]

    implicit def wrapT3_P1_P2[F[_], G[_], A](value: (F[A], G[A], A)): Type.Tuple3[F, G, Id] =
    value.asInstanceOf[Type.Tuple3[F, G, Id]]


    implicit def unwrap[F[_]](value: Type[F]): F[value.T] =
    value.asInstanceOf[F[value.T]]

    implicit def unwrapT2[F[_], G[_]](value: Type.Tuple2[F, G]): (F[value.T], G[value.T]) =
    value.asInstanceOf[(F[value.T], G[value.T])]

    implicit def unwrapT3[F[_], G[_], H[_]](value: Type.Tuple3[F, G, H]): (F[value.T], G[value.T], H[value.T]) =
    value.asInstanceOf[(F[value.T], G[value.T], H[value.T])]

    关于scala - 如何在 Scala 3/Dotty 中实现像 MapK 这样的类型?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/67750145/

    26 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com