我正在尝试在Scala中实现Absurd
typeclass (as seen in Haskell's Data.Boring library)。
我能够为Absurd
定义Absurd
实例。不幸的是,当我尝试为Nothing
定义一个荒谬的实例时,我得到了一个丢失的隐式错误
Either
此编译:
sealed trait Absurd[A] {
def absurd[X](a: A): X
}
object Absurd {
def apply[A: Absurd, B](a: A):B = implicitly[Absurd[A]].absurd[B](a)
implicit val absurdForNothing: Absurd[Nothing] = new Absurd[Nothing]{
override def absurd[X](a: Nothing): X = a
}
implicit def absurdForEither[A: Absurd, B: Absurd]: Absurd[Either[A, B]] = new Absurd[Either[A, B]]{
override def absurd[X](a: Either[A,B]): X = a match {
case Left(a) => Absurd[A, X](a)
case Right(b) => Absurd[B, X](b)
}
}
}
此无法编译:
implicitly[Absurd[Nothing]]
我正在使用Scala版本“ 2.13.2”。
可能有趣的是,以下非常相似的代码(不涉及implicitly[Absurd[Either[Nothing, Nothing]]]
)可以编译:
Nothing
由于Dmytro的评论,我能够为此trait SomeTypeclass[A]
case class SomeInstance()
object SomeTypeclass {
implicit val someTypeclassForSomeInstance: SomeTypeclass[SomeInstance] = new SomeTypeclass[SomeInstance] {}
implicit def someTypeclassForEither[A: SomeTypeclass, B: SomeTypeclass]: SomeTypeclass[Either[A, B]] = new SomeTypeclass[Either[A, B]] {}
}
object SomeApplicationCode {
implicitly[SomeTypeclass[Either[SomeInstance, SomeInstance]]]
}
找到this post suggesting a workaround。
总之,我们可以为bug的子类型定义类型别名[C0
Empty.T
由于Nothing
没有值,也没有子类型,因此object Empty{
type T <: Nothing
}
也将没有值。这使我们可以编写荒诞的实例:
Nothing
这有效!以下将编译:
Empty.T
由于我正在移植Haskell代码,而不必担心差异,因此将我们自己的空类型定义为替代方法同样有效:
object Absurd {
def apply[A: Absurd, B](a: A):B = implicitly[Absurd[A]].absurd[B](a)
implicit val absurdForEmptyT: Absurd[Empty.T] = new Absurd[Empty.T]{
override def absurd[X](a: Empty.T): X = a
}
implicit def absurdForEither[A:Absurd, B: Absurd]: Absurd[Either[A, B]] = new Absurd[Either[A, B]]{
override def absurd[X](a: Either[A,B]): X = a match {
case Left(a) => Absurd[A,X](a)
case Right(b) => Absurd[B, X](b)
}
}
}
这可行,但是我个人更喜欢第一种方法,因为它不会忽略Scala中已经内置的Empty类型implicitly[Absurd[Either[Empty.T, Empty.T]]]
,并且它不依赖我们使用sealed trait Empty
object Absurd {
def apply[A: Absurd, B](a: A):B = implicitly[Absurd[A]].absurd[B](a)
implicit val absurdForEmpty: Absurd[Empty] = new Absurd[Empty]{
override def absurd[X](a: Empty): X = ???
}
// ...
}
来写初始[ C0]实例。