尝试实现`Absurd`类型类时出现隐式错误

问题描述 投票:4回答:1

我正在尝试在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
scala typeclass implicit bottom-type
1个回答
0
投票

由于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]实例。

© www.soinside.com 2019 - 2024. All rights reserved.