代码之家  ›  专栏  ›  技术社区  ›  alphacentauri

HOMap实现示例

  •  1
  • alphacentauri  · 技术社区  · 10 年前

    我在看 this video by Daniel Spiewak 并尝试从中实现关于更高种类的示例

    /* bad style */
    
    val map: Map[Option[Any], List[Any]] = Map (
      Some("foo") -> List("foo", "bar", "baz"),
      Some(42) -> List(1, 1, 2, 3, 5, 8),
      Some(true) -> List(true, false, true, false)
    )
    
    val xs: List[String] =
      map(Some("foo")).asInstanceOf[List[String]]  // ugly cast                                                                                                                                       
    val ys: List[Int] =
      map(Some(42)).asInstanceOf[List[Int]]  // another one                                                                                                                                           
    
    println(xs)
    println(ys)
    
    /* higher kinds usage */
    
    // HOMAP :: ((* => *) x (* => *)) =>     *                                                                                                                                                            
    class HOMap[K[_], V[_]](delegate: Map[K[Any], V[Any]]) {
      def apply[A](key: K[A]): V[A] =
        delegate(key.asInstanceOf[K[Any]]).asInstanceOf[V[A]]
    }
    
    object HOMap {
      type Pair[K[_], V[_]] = (K[A], V[A]) forSome { type A }
    
      def apply[K[_], V[_]](tuples: Pair[K, V]*) =
        new HOMap[K, V](Map(tuples: _*))
    }
    
    val map_b: HOMap[Option, List] = HOMap[Option, List](
      Some("foo") -> List("foo", "bar", "baz"),
      Some(42) -> List(1, 1, 2, 3, 5, 8),
      Some(true) -> List(true, false, true, false)
    )
    
    val xs_b: List[String] = map_b(Some("foo"))
    
    val ys_b: List[Int] = map_b(Some(42))
    
    println(xs_b)
    println(ys_b)
    

    不幸的是,启动此程序时,我遇到类型不匹配错误:

    username@host:~/workspace/scala/samples$ scala higher_kinds.scala
    /home/username/workspace/scala/samples/higher_kinds.scala:30: error: type mismatch;
     found   : Main.$anon.HOMap.Pair[K,V]*
     required: Seq[(K[Any], V[Any])]
         new HOMap[K, V](Map(tuples: _*))
                        ^
    one error found
    

    我的问题:

    1. 我怎样才能解决这个问题?我完全理解我只需要传入正确的类型,但我在Scala中使用此类内容的经验很差,我无法理解这一点。
    2. 为什么会发生这种情况?我指的是手术 tuples: _* 可能广泛用于传递给 Map 但不知怎么的,它给人一种奇怪的感觉- Main.$anon.HOMap.Pair[K,V]* 而不是它应该给予的。
    3. 为什么这个例子不再有效?也许Scala语言最近的一些变化改变了一些语法?

    谢谢回答!

    1 回复  |  直到 10 年前
        1
  •  2
  •   Yuriy    10 年前

    类型变化条件中的问题。在线 def apply[K[_], V[_]] 你需要保证集装箱 K[_] & V[_] 可以被铸造成 K[Any] & V[Any]

    只需添加类型covalence约束( + )至K&V容器:

    object HOMap {
      def apply[K[+_], V[+_]](tuples: (Pair[K[A], V[A]] forSome { type A })*) =
        new HOMap[K, V](Map(tuples: _*))
    }