Благодаря комментарию Дмитрия мне удалось найти этот пост, предлагающий обходной путь для этой ошибки .
Короче говоря, мы можем определить псевдоним типа Empty.T
для подтипов Nothing
object Empty{
type T <: Nothing
}
Поскольку Nothing
не имеет значений и подтипов, Empty.T
также будет не имеют ценностей. Это позволяет нам писать наши экземпляры Absurd:
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)
}
}
}
Это работает! Следующее будет компилироваться:
implicitly[Absurd[Either[Empty.T, Empty.T]]]
как и:
implicitly[Absurd[Either[Nothing, Nothing]]]
Поскольку я портирую код Haskell, который не должен беспокоиться о дисперсии, он в равной степени можно было бы определить наш собственный пустой тип в качестве обходного пути:
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 = ???
}
// ...
}
Это работает, но лично я предпочитаю первый подход, поскольку он не игнорирует пустой тип Nothing
, который уже встроен в Scala, и поскольку он не требует от нас использования ???
для записи начального экземпляра Absurd[Empty]
.