根据用户为 "A" 和 "B" 定义的隐式解析 "A with B" 的隐式

resolve implicit for "A with B" based on user defined implicits for "A" and "B"

为了通过虚拟类型参数而不是单独的域类型使域对象状态显式化,我想出了一个这样的模型:

sealed trait State

sealed trait Verified extends State

sealed trait Contactable extends State

class Name[+S <: State](val name: String)

class User[S <: State] {
  def state(implicit n: Name[S]): String = n.name
}

implicit def verifiedName: Name[Verified] = new Name[Verified](name = "verified")
implicit def contactableName: Name[Contactable] = new Name[Contactable](name = "contactable")
implicit def nameAB[A <: State, B <: State](implicit s1: Name[A], s2: Name[B]): Name[A with B] = 
    new Name[A with B](name = s1.name concat " & " concat s2.name)

//client code
new User[Verified].state //Check!
new User[Contactable].state //Check!
new User[Contactable with Verified].state //Epic Fail!
//Error:(20, 38) diverging implicit expansion for type
// A$A516.this.Name[A$A516.this.Contactable with A$A516.this.Verified]
//starting with method nameAB in class A$A516
//new User[Contactable with Verified].state;}

总的来说,我想要实现的是可交换操作的行为自动组合。在这种情况下,我需要 Userstate 方法,状态 Contactable with Verified 为 "contactable & verified" 甚至 "verified & contactable"。 Scala 的类型系统对我来说太多了。所以我无法弄清楚问题所在。如果可以解决我该怎么做?如果不是,是什么原因?

一个可能的解决方案在我的情况下,实现组合是主要目标,将 A with B 替换为 (A,B) 来表达组合解决了问题:

sealed trait State

trait Verified extends State

trait Contactable extends State

class Name[S](val name: String)

class User[S] {
  def state(implicit n: Name[S]): String = n.name
}

implicit def aName: Name[Verified] = new Name[Verified](name = "verified")
implicit def bName: Name[Contactable] = new Name[Contactable](name = "contactable")
implicit def nameAB[A, B](implicit s1: Name[A], s2: Name[B]): Name[(A, B)] =
  new Name[(A, B)](name = s1.name concat " & " concat s2.name)

//client code
new User[Verified].state //Check!
new User[Contactable].state //Check!
new User[(Contactable, Verified)].state // Check!

从这一点开始,可以为 Tuple3, Tuple4 , ... 的情况定义其他隐式或使用嵌套的 tuple2s 来扩展组合。 对于 A with B

的情况,我还没有答案

我个人认为您将隐式解析的概念与幻像类型混为一谈。从更简单的变体中为复合类型派生隐式是一个有据可查的过程,您可以将记录类型编码为 HList 并派生为 HList ,或者求助于隐式宏,这实际上在没有无形糖的情况下做同样的事情.

Phantom 类型是关于静态的(在编译时)"mutating" class 上的类型参数以在编译时对某些状态进行编码,并且它通常不会像您建议的那样与隐式混合。我的意思是:

trait State
trait Contacted extends State
trait Verifiable extends State


class Builder[C <: State, V <: State] {
  // In here I statically alter the signature of `Builder`
  // telling the compiler a call to `addContact`
  // will alter the type arg to the value of `Contacted`
  def addContact: Builder[Contacted, V]
  def verify(input: Whatever)(
    implicit ev: C =:= Contacted
  ): Builder[Contacted, Verifiable] = ???
}

在上述情况下,编译器现在会阻止您在 addContact 之前调用 verifiable。并且此方法的任何后来用户,如果说您正在构建一个框架,如果他们试图做一些被认为无效的事情,就会得到一个编译时错误。

所以诀窍是不要尝试统一每个人的类型,尽管你可以,但它可能会增加比你想象的更多的下游复杂性。对于幻像类型,您通常有 "one per state".