强制依赖返回类型必须实现typeclass [英] Enforcing that dependent return type must implement typeclass

查看:106
本文介绍了强制依赖返回类型必须实现typeclass的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试执行一个规则,即类型类的(依赖)返回类型本身必须实现一个类型类.因此,当用户实现下面的IsVec类型类时,他们还必须确保getElem方法的返回值实现另一个类型类(IsVecElem).我试图使这项工作看起来像这样:

// A typeclass for an vector element
abstract class IsVecElem[A, T: Numeric] {
  def dataOnly(self: A): T
}
// A typeclass for a vector
abstract class IsVec[A, T: Numeric] {
  // I would like this OutElem output type to implement the IsVecElem typeclass
  protected type OutElem
  def getElem(self: A, i: Int)(implicit tcO: IsVecElem[OutElem, T]): OutElem
}
// give this typeclass method syntax
implicit class IsVecOps[A, T: Numeric](value: A) {
  def getElem(i: Int)(implicit tcA: IsVec[A, T], tcO: IsVecElem[tcA.OutElem, T]) = tcA.getElem(value, i)
}

问题与IsVecOps中的getElem一起出现-引发了编译错误:

type OutElem in class IsVec cannot be accessed as a member of IsVec[A, T] from class IsVecOps. Access to protected type OutElem not permitted because enclosing class IsVecOps is not a subclass of class IsVec

具有IsVecOps扩展IsVec并不是一个立即解决方案,并且感觉不应该,所以我想知道代码中其他地方的方法是否有错误.

非常感谢任何帮助.

解决方案

IsVecOps不应扩展IsVec.隐式类(仅旨在引入扩展方法)扩展类型类将非常奇怪.

如果暂时删除访问修饰符(protected),您将看到错误消息更改为

illegal dependent method type: parameter may only be referenced in a subsequent parameter section
    def getElem...

尝试添加类型参数(OE)并指定类型细化(IsVec[A, T] { ... })

implicit class IsVecOps[A, T: Numeric](value: A) {
  def getElem[OE](i: Int)(implicit tcA: IsVec[A, T] { type OutElem = OE }, tcO: IsVecElem[OE, T]): OE = tcA.getElem(value, i)
}

如果您介绍Aux -type

object IsVec {
  type Aux[A, T, OE] = IsVec[A, T] { type OutElem = OE }
}

然后您可以更紧凑地重写类型细化

implicit class IsVecOps[A, T: Numeric](value: A) {
  def getElem[OutElem](i: Int)(implicit tcA: IsVec.Aux[A, T, OutElem], tcO: IsVecElem[OutElem, T]): OutElem = tcA.getElem(value, i)
}

我如何拥有一个类型参数取决于隐式参数的方法参数?

Shapeless何时需要依赖类型?

为什么类型-级别的计算?

了解Scala类型系统中的Aux模式

Dotty 中,您将可以使用特征参数,扩展方法,多个隐式参数列表,同一参数列表中的参数类型相互依赖:

trait IsVecElem[A, T: Numeric] {
  def dataOnly(self: A): T
}
  
trait IsVec[A, T: Numeric] {
  protected type OutElem
  def (self: A) getElem(i: Int)(using IsVecElem[OutElem, T]): OutElem
}

trait IsVecElem[A, T: Numeric] {
  def dataOnly(self: A): T
}

trait IsVec[A, T: Numeric] {
  /*protected*/ type OutElem
  def getElem(self: A, i: Int)(using IsVecElem[OutElem, T]): OutElem
}
extension [A, T: Numeric](value: A) {
  def getElem(i: Int)(using tcA: IsVec[A, T], tcO: isVecElem[tcA.OutElem, T]) = tcA.getElem(value, i)
}

(在0.28.0-bin-20200908-ce48f5a-NIGHTLY中测试)

I am trying to enforce a rule that the (dependent) return type of a typeclass, must itself implement a typeclass. So when the user implements the IsVec typeclass below, they must also ensure that the return value of the getElem method implements another typeclass (IsVecElem). My attempts to make this work look something like this:

// A typeclass for an vector element
abstract class IsVecElem[A, T: Numeric] {
  def dataOnly(self: A): T
}
// A typeclass for a vector
abstract class IsVec[A, T: Numeric] {
  // I would like this OutElem output type to implement the IsVecElem typeclass
  protected type OutElem
  def getElem(self: A, i: Int)(implicit tcO: IsVecElem[OutElem, T]): OutElem
}
// give this typeclass method syntax
implicit class IsVecOps[A, T: Numeric](value: A) {
  def getElem(i: Int)(implicit tcA: IsVec[A, T], tcO: IsVecElem[tcA.OutElem, T]) = tcA.getElem(value, i)
}

The problem comes with getElem in IsVecOps - this raises a compile error:

type OutElem in class IsVec cannot be accessed as a member of IsVec[A, T] from class IsVecOps. Access to protected type OutElem not permitted because enclosing class IsVecOps is not a subclass of class IsVec

Having IsVecOps extend IsVec isn't an immediate solution and doesn't feel like it should be, so I'm wondering if there's an error in approach elsewhere in the code.

Any help much appreciated.

解决方案

IsVecOps shouldn't extend IsVec. Implicit class (with the only purpose to introduce an extension method) extending a type class would be very strange.

If for a moment you remove access modifier (protected) you'll see that the error message changes to

illegal dependent method type: parameter may only be referenced in a subsequent parameter section
    def getElem...

Try to add a type parameter (OE) and specify type refinement (IsVec[A, T] { ... })

implicit class IsVecOps[A, T: Numeric](value: A) {
  def getElem[OE](i: Int)(implicit tcA: IsVec[A, T] { type OutElem = OE }, tcO: IsVecElem[OE, T]): OE = tcA.getElem(value, i)
}

If you introduce Aux-type

object IsVec {
  type Aux[A, T, OE] = IsVec[A, T] { type OutElem = OE }
}

then you can rewrite type refinement more compactly

implicit class IsVecOps[A, T: Numeric](value: A) {
  def getElem[OutElem](i: Int)(implicit tcA: IsVec.Aux[A, T, OutElem], tcO: IsVecElem[OutElem, T]): OutElem = tcA.getElem(value, i)
}

How can I have a method parameter with type dependent on an implicit parameter?

When are dependent types needed in Shapeless?

Why is the Aux technique required for type-level computations?

Understanding the Aux pattern in Scala Type System

In Dotty you'll be able to use trait parameters, extension methods, multiple implicit parameter lists, types of parameters in the same parameter list dependent on each other:

trait IsVecElem[A, T: Numeric] {
  def dataOnly(self: A): T
}
  
trait IsVec[A, T: Numeric] {
  protected type OutElem
  def (self: A) getElem(i: Int)(using IsVecElem[OutElem, T]): OutElem
}

or

trait IsVecElem[A, T: Numeric] {
  def dataOnly(self: A): T
}

trait IsVec[A, T: Numeric] {
  /*protected*/ type OutElem
  def getElem(self: A, i: Int)(using IsVecElem[OutElem, T]): OutElem
}
extension [A, T: Numeric](value: A) {
  def getElem(i: Int)(using tcA: IsVec[A, T], tcO: isVecElem[tcA.OutElem, T]) = tcA.getElem(value, i)
}

(tested in 0.28.0-bin-20200908-ce48f5a-NIGHTLY)

这篇关于强制依赖返回类型必须实现typeclass的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆