Scala 无形状:这两种实例派生方法之间有什么区别?
有人能解释一下这两种类型类实例派生方法(特别是选项[A])之间的区别吗 一,Scala 无形状:这两种实例派生方法之间有什么区别?,scala,typeclass,shapeless,deriving,generic-derivation,Scala,Typeclass,Shapeless,Deriving,Generic Derivation,有人能解释一下这两种类型类实例派生方法(特别是选项[A])之间的区别吗 一, trait MyTrait[A]{…} 对象MyTrait扩展了低优先级{ //基本体的实例 } 特征低优先级扩展了低优先级{ final implicit def generic[A,H实际上,如果没有右侧和实际实现,很难说 从您提供的信息来看,这两个类型类的行为并不等同 例如,在第一种方法中,你考虑一些特殊的情况,所以理论上,你可能在不同的情况下重新定义一些一般的行为。 顺便说一下,选项[A]是一些[A]和无的副产
trait MyTrait[A]{…}
对象MyTrait扩展了低优先级{
//基本体的实例
}
特征低优先级扩展了低优先级{
final implicit def generic[A,H实际上,如果没有右侧和实际实现,很难说
从您提供的信息来看,这两个类型类的行为并不等同
例如,在第一种方法中,你考虑一些特殊的情况,所以理论上,你可能在不同的情况下重新定义一些一般的行为。
顺便说一下,
选项[A]
是一些[A]
和无的副产品。type
(List[A]
是scala:[A]
和Nil.type
)的副产品,有时为副产品派生类型类比为选项[A]
(或List[A]
)更容易。“正确工作”是指“已编译”或“为某个简单用例工作”
您的两个示例都涉及泛型乘积类型,但不涉及泛型求和类型,因此不存在使用Some[A]:+:None:+:CNil
派生出例如Option[A]
的风险,这会造成一些歧义。因此(据我所知),您可以编写第二个版本,如:
trait MyTrait[A] {...}
object MyTrait extends LowPriority {
// instances for primitives
// deriving instances for options from existing non-option instances
final implicit def forOption[A](implicit instance: MyTrait[A]): MyTrait[Option[A]] = ???
}
trait LowPriority {
// <<<----
final implicit def hcons[A, H <: HList](
implicit gen: Generic.Aux[A, H],
h: Lazy[MyTrait[H]]
): MyTrait[A] = ???
final implicit val hnil: MyTrait[HNil] = ???
final implicit def product[H, T <: HList](
implicit h: Lazy[MyTrait[H]],
t: Lazy[MyTrait[T]]
): MyTrait[H :: T] = ???
}
因此,使用隐式def forOption[A](隐式实例:MyTrait[A]):MyTrait[Option[A]]
的任何解决方案都更简单、更可靠
根据您直接放入同伴低优先级的内容,可能需要也可能不需要:
- 如果定义了副产品,则手动支持,例如,
选项
,列表
,或
可能与不成形的派生产品冲突
- 如果手动为其伴生对象中的某个类型实现了
MyTrait
隐式,那么它将具有与直接在MyTrait
中隐式相同的优先级-因此,如果它可以使用shapeless派生,则可能会有冲突
出于这个原因,将无形状隐式放在LowPriorityInflicits
中是有意义的,但将原语和列表、选项等的手动编解码器直接放在companion中是有意义的。也就是说,除非您在companion中定义了一些,例如选项[String]
隐式,这可能与“选项[A]冲突
带有隐式forA
”
由于我不知道您的确切用例,我无法确定,但我可能会选择秒方法,或者最有可能的方法是我在上面的代码片段中实现的方法。谢谢!关于第一个版本-我第一次在doobie
项目中看到这一点,当时我试图了解它如何与Shapess()在那之后,我试图实现一些类似的东西,但对这种方法有一个特别的疑问,因为我从未在许多Shapess的示例/教程中看到过这一点。我认为在Doobie的例子中,这是需要的。在那里,“Write[Option[a]]
fromPut[a]
“可能用于原语,而在选项[H::T]
中添加值时,可用于在添加选项[H]
(其中处理null
不需要将整个最终结果置零)或非选项
H
(例如,一个字段中的null
可能不会导致整个Repr
/A
)。因此,我们在这里期望的行为是不同的。因此,这三个层是有意义的:如果您有Put[A]
,请将其提升到Write[Option[A]
(同伴),如果要处理非可选产品,请在任何字段上使用派生,如果存在选项[a],则任何字段上的null
都会导致错误(优先级较低)
如果A
是产品类型,则可以处理选项
字段上的null,但非可选字段上的null
将是整个A
的None
(甚至更低优先级)。将EvenLower与Lower放在同一级别可能会导致选项
派生冲突。谢谢!这对于理解没有问题至关重要,尽管这只是一个没有任何调查的猜测,所以不要将其视为一个确定的答案,更像是一个探索建议。谢谢!在我的情况下,它似乎会产生同样的结果
trait MyTrait[A] {...}
object MyTrait extends LowPriority {
// instances for primitives
}
trait LowPriority {
// deriving instances for options from existing non-option instances
final implicit def forOption[A](implicit instance: MyTrait[A]): MyTrait[Option[A]] = ??? // <<<----
final implicit def generic[A, H <: HList](
implicit gen: Generic.Aux[A, H],
h: Lazy[MyTrait[H]]
): MyTrait[A] = ???
final implicit val hnil: MyTrait[HNil] = ???
final implicit def product[H, T <: HList](
implicit h: Lazy[MyTrait[H]],
t: Lazy[MyTrait[T]]
): MyTrait[H :: T] = ???
}
trait MyTrait[A] {...}
object MyTrait extends LowPriority {
// instances for primitives
// deriving instances for options from existing non-option instances
final implicit def forOption[A](implicit instance: MyTrait[A]): MyTrait[Option[A]] = ???
}
trait LowPriority {
// <<<----
final implicit def hcons[A, H <: HList](
implicit gen: Generic.Aux[A, H],
h: Lazy[MyTrait[H]]
): MyTrait[A] = ???
final implicit val hnil: MyTrait[HNil] = ???
final implicit def product[H, T <: HList](
implicit h: Lazy[MyTrait[H]],
t: Lazy[MyTrait[T]]
): MyTrait[H :: T] = ???
}
class MyCustomType
object MyCustomType {
implicit val myTrait: MyTrait[MyCustomType]
}
implicitly[Option[MyCustomType]]