繁体   English   中英

Scala 中的幻影存在类型

[英]Phantom existential types in Scala

我正在尝试编写一个值 class 来包装 Scala 集合的Map并提供替代get 我正在尝试在值 class 中使用幻像类型,并使用方法member标记具有相同类型的Key 如果member的结果是Some(k)那么用户应该能够调用get(k)并获得V而不是Option[V]

import scala.collection.{Map => M}

class Key[PH, K] private (val k: K) extends AnyVal

object Key {
  def apply[PH, K](k: K): Key[PH, K] = new Key(k)
}

class Map[PH, K, V] private (val m: M[K, V]) extends AnyVal {
  def member(k: K): Option[Key[PH, K]] = m.get(k).map(_ => Key(k))

  def get(key: Key[PH, K]): V = m.get(key.k).get
}

object Map {
  def apply[PH, K, V](m: M[K, V]): Map[PH, K, V] = new Map(m)
}

def withMap[K, V, T](m: M[K, V])(cont: (Map[PH, K, V] forSome { type PH }) => T): T = cont(Map(m))

withMap(M("a" -> "a")){ m =>
  m.member("a") match {
    case Some(v) => println(m.get(v))
    case None => println(":(")
  }
}

但目前它无法编译并出现以下错误:

found   : Key[PH(in value $anonfun),String] where type +PH(in value $anonfun)
required: Key[PH(in value cont),String]
    case Some(v) => println(m.get(v))

我怎样才能让 scalac 相信PH是相同的?

解构存在主义:

withMap(M("a" -> "a")) { case m =>
  m.member("a") match {
    case Some(v) => println(m.get(v))
    case None => println(":(")
  }
}

这缩写

withMap(M("a" -> "a")) { case m: Map[ph, String, String] => // name the phantom type ph, name the map m =>
  m.member("a") match {
    case Some(v) => println(m.get(v))
    case None => println(":(")
  }
}

根据新引入的类型变量,解构允许m被赋予一个不存在的类型。 这意味着每次出现的m现在都可以具有相同的类型。

幽灵类型是没有意义的。 你应该说出你的意思:每个Key都属于某个Map

import scala.collection.immutable.Map // it is not safe to use Maps in general!

class KeyedMap[K, V](val m: Map[K, V]) extends AnyVal {
  import KeyedMap._
  def member(k: K): Option[Key[K, V, m.type]] = m.get(k).map { _ => new Key[K, V, m.type](k) }
  def fromKey(k: Key[K, V, m.type]): V = m(k.k)
}
object KeyedMap {
  //                              vvvvvvvvvvvvvv requires this parameter to be <something>.type
  class Key[K, +V, M <: Map[K, V] with Singleton] private[KeyedMap](val k: K) extends AnyVal
}

object Test {
  def main(args: String*): Unit = {
    val m = new KeyedMap(Map("a" -> "b"))
    m.member("a") match {
      case Some(v) => println(m.fromKey(v))
      case None => println(":(")
    }
  }
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM