簡體   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