首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何使用路径相关类型类

如何使用路径相关类型类
EN

Stack Overflow用户
提问于 2020-04-05 17:43:15
回答 3查看 90关注 0票数 0

我试图在方法中使用依赖于类型的类型类,如下所示:

代码语言:javascript
复制
@typeclass trait Identifiable[M] {
  type K
  def identify(id: M): K
}

object Identifiable {
  type Aux[M, K0] = Identifiable[M] { type K = K0 }
  implicit def identifiableTuple[K1, K2](
      implicit
      a: Identifiable[K1],
      b: Identifiable[K2]
  ): Identifiable.Aux[(K1, K2), (a.K, b.K)] = new Identifiable[(K1, K2)] {
    type K = (a.K, b.K)
    override def identify(id: (K1, K2)): K = {
      val k1 = a.identify(id._1)
      val k2 = b.identify(id._2)
      (k1, k2)
    }
  }

但是,当我尝试像下面这样使用它时,隐式参数不会被解析。

代码语言:javascript
复制
def a[K: Identifiable](key:K) = { 
case k => 
 val keyString: String = the[Identifiable.Aux[K, String]].identify(key) 
case (k1,k2) => 
 val keyString: (String,String) = the[Identifiable.Aux[K, (String, String)]].identify(key) }
EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2020-04-05 17:55:32

您要求在类型约束中使用路径依赖类型隐式,但随后调用该类型的隐式,该类型固定在某物上。

为此,编译器必须能够证明可识别的依赖类型等于K,这在当前代码中是无法做到的。

你可以试试:

ev: identifiable.K =:= K

  • 在两处使用相同的约定(无论是使用Aux还是都使用相依类型),
  • 证明了依赖类型与隐含证据
  • 中的K相等
票数 2
EN

Stack Overflow用户

发布于 2020-04-05 18:01:26

模式(k1,k2)应该在无约束模式k之前,否则一切都会转到k,而不是(k1,k2)

模式匹配主要在运行时工作,类型类/隐式大部分在编译时工作。由于您开始使用类型类(此外,使用带有类型成员的类型类),所以您似乎希望在编译时对类型进行一些计算,即一些计算。

运行时的逻辑分支对应于模式匹配。编译时的逻辑分支对应于一个类型类,并且有几个类型类的定义实例。

尝试使a()成为一个类型类

代码语言:javascript
复制
trait A[K] {
  def apply(key: K): Unit
}

object A {
  implicit def tupleA[K](implicit identifiable: Identifiable.Aux[K, (String, String)]): A[K] = new A[K] {
    override def apply(key: K): Unit = key match {
      case (k1, k2) =>
        val keyString: (String, String) = identifiable.identify(key)
        ()
    }
  }

  implicit def defaultA[K](implicit identifiable: Identifiable.Aux[K, String]): A[K] = new A[K] {
    override def apply(key: K): Unit = {
      val keyString: String = identifiable.identify(key)
      ()
    }
  }
}

def a[K](key: K)(implicit aInstance: A[K]) = aInstance(key)

您应该编写一些示例,说明您计划如何应用a()。关于什么输入,你期望什么输出。应该编译什么,不应该编译什么?

通常类型参数(如M表示Identifiable[M])类似于输入,类型成员(如K表示Identifiable[M] { type K })类似于类型级计算的输出。因此,对于Identifiable,看起来K类型将被选择为M类型。这是正确的吗?请考虑你的逻辑(什么是输入,什么输出)。在a()中,您似乎开始根据K的类型来做一些事情。

票数 1
EN

Stack Overflow用户

发布于 2020-04-05 18:17:13

但你为什么要指望他们能匹配呢?在case k =>分支中,存在类型为Identifiable[K]的隐式,但没有理由期望它是您试图用the请求的Identifiable[K] { type K = String }。或者是另一个分支中的Identifiable[K] { type K = (String, String) }。(请注意,K有两个不同的含义,这可能有点让人困惑。)

来自注释case类K1(值: String);case类K2(值: String)我期望: a(K1) =>字符串和((K1,K2)) => ( String,String)

最合理的选择接近你想要的似乎是简单的

代码语言:javascript
复制
def a[A](key:A)(implicit ev: Identifiable[A]): ev.K = ev.identify(key)
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/61046802

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档