根据用户为 "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;}
总的来说,我想要实现的是可交换操作的行为自动组合。在这种情况下,我需要 User
的 state
方法,状态 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 , ...
的情况定义其他隐式或使用嵌套的 tuple2
s 来扩展组合。
对于 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".
为了通过虚拟类型参数而不是单独的域类型使域对象状态显式化,我想出了一个这样的模型:
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;}
总的来说,我想要实现的是可交换操作的行为自动组合。在这种情况下,我需要 User
的 state
方法,状态 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 , ...
的情况定义其他隐式或使用嵌套的 tuple2
s 来扩展组合。
对于 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".