Home > OS >  Using Cats Show on enum
Using Cats Show on enum

Time:02-17

I need to implement the cats Show instances for an enum which express the basic operators.

enum Expr[T]:

  case Plus(left: Expr[Double], right: Expr[Double]) extends Expr[Double]
  case Minus(left: Expr[Double], right: Expr[Double]) extends Expr[Double]
  case Num(value: Double) extends Expr[Double]


object Expr {

  def eval[T](expr: Expr[T]): T =
    expr match {
      case Plus(left, right)         => eval(left)   eval(right)
      case Minus(left, right)        => eval(left) - eval(right)
      case Num(value)                => value
    }

After reading the doc, I tried to implement as following:

object ExprShow {
  implicit val numShow: Show[Expr.Num] = Show.show(
    num => num.value.toString
  )

  implicit val minusShow: Show[Expr.Minus] = Show.show(
    minus => show"${minus.left} - ${minus.right}"
  )

  implicit val plusShow: Show[Expr.Plus] = Show.show(
    plus => show"${plus.left}   ${plus.right}"
  )
}

But I got the errors when trying to execute the show method:

val test = Expr.Num(3.0)
test.show
[error] -- [E007] Type Mismatch Error: 
[error] 69 |    minus => show"${minus.left} - ${minus.right}"
[error]    |                    ^^^^^^^^^^
[error]    |                    Found:    (minus.left : grox.Expr[Double])
[error]    |                    Required: cats.Show.Shown
[error] Explanation
[error] ===========
[error] 
[error] Tree: minus.left
[error] 
[error] I tried to show that
[error]   (minus.left : grox.Expr[Double])
[error] conforms to
[error]   cats.Show.Shown
[error] but the comparison trace ended with `false`:
[error]           
[error]   ==> (minus.left : grox.Expr[Double])  <:  cats.Show.Shown
[error]     ==> (minus.left : grox.Expr[Double])  <:  cats.Show.Shown (recurring)
[error]       ==> grox.Expr[Double]  <:  cats.Show.Shown (left is approximated)
[error]         ==> grox.Expr[Double]  <:  cats.Show.Shown (recurring)
[error]         <== grox.Expr[Double]  <:  cats.Show.Shown (recurring) = false
[error]       <== grox.Expr[Double]  <:  cats.Show.Shown (left is approximated) = false
[error]     <== (minus.left : grox.Expr[Double])  <:  cats.Show.Shown (recurring) = false
[error]   <== (minus.left : grox.Expr[Double])  <:  cats.Show.Shown = false
[error] 
[error] The tests were made under a constraint with:
[error]  uninstantiated variables: A
[error]  constrained types: [A](f: A => String): cats.Show[A], 
[error]   [A](f: A => String): cats.Show[A]
...
----------
[error] -- [E008] Not Found Error: 
[error] 15 |    test.show
[error]    |    ^^^^^^^^^
[error]    |    value show is not a member of grox.Expr[Double]

Is there any best practice approach to implement cats Show for enum? What's the root cause of my issue? Any suggestions or doc recommendation would be appreciated. Thanks a bunch

CodePudding user response:

implicit val minusShow: Show[Expr.Minus] = Show.show(
    minus => show"${minus.left} - ${minus.right}"
  )

minus.left type is Expr[Double], you should define Show[Expr[Double]] first so it could find the correct implicit.

Here is the solution

implicit def exprShow[T]: Show[Expr[T]] = Show.show(
      num => Expr.eval(num).toString
    )
  • Related