You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Kittens自动推导Show时未复用NonEmptyList已有实例问题咨询

问题:Kittens自动推导Show实例时未复用已有隐式实例的解决方法

问题代码

package domain

import cats.{Show, derived}
import cats.data.NonEmptyList
import cats.implicits._

case class Error(code: String, message: String)

case class Errors(errors: NonEmptyList[Error])

object ShowStuffApp {

//  import NonEmptyList.catsDataShowForNonEmptyList
  
  implicit val show: Show[Errors] = derived.semiauto.show

  def main(args: Array[String]): Unit = {
    val errors = Errors(NonEmptyList.one(Error("1234", "Could not process")))
    val res = errors.show
    println(res)
  }
}

运行输出

Errors(errors = NonEmptyList(head = Error(code = 1234, message = Could not process), tail = Nil$()))

问题说明

这段代码运行后,Kittens自动为NonEmptyList推导了一个Show实例,而非使用通过cats.implicits._导入的官方隐式实例;就算取消注释内部的import NonEmptyList.catsDataShowForNonEmptyList也没用。但Kittens文档明确说自动推导时会尊重已有的隐式实例,该怎么解决?


解决方案

问题根源

Kittens的derived.semiauto.show在推导嵌套类型的Show实例时,会优先尝试为嵌套类型(这里是NonEmptyList[Error])自动推导实例,而不是优先查找当前作用域中已有的隐式——因为推导Errors的Show时,Error的Show实例也需要被推导,整个推导上下文的隐式查找逻辑和常规隐式查找优先级不同。

具体解决步骤

  1. 先为嵌套的Error类型定义Show实例
    确保Error的Show实例先存在于作用域中,这样推导NonEmptyList[Error]的Show时,会先找到Error的实例,再结合已有的NonEmptyList官方Show实例生成正确的实例。
    可以自动推导:

    implicit val errorShow: Show[Error] = derived.semiauto.show
    

    也可以手动定义:

    implicit val errorShow: Show[Error] = Show.show(e => s"Error(code=${e.code}, message=${e.message})")
    
  2. 确保NonEmptyList的官方Show实例在推导Errors时可见
    在定义Errors的Show实例之前,明确导入NonEmptyList的Show实例,或者确保cats.implicits._的导入在推导代码之前。

修改后的完整代码

package domain

import cats.{Show, derived}
import cats.data.NonEmptyList
import cats.implicits._

case class Error(code: String, message: String)
// 先定义Error的Show实例
implicit val errorShow: Show[Error] = derived.semiauto.show

case class Errors(errors: NonEmptyList[Error])

object ShowStuffApp {
  // 显式导入NonEmptyList的官方Show实例,确保推导时能找到
  import NonEmptyList.catsDataShowForNonEmptyList
  
  implicit val errorsShow: Show[Errors] = derived.semiauto.show

  def main(args: Array[String]): Unit = {
    val errors = Errors(NonEmptyList.one(Error("1234", "Could not process")))
    println(errors.show)
  }
}

另一种显式指定的方式

如果不想依赖导入顺序,可以在推导Errors的Show时,显式传入NonEmptyList[Error]的隐式实例:

implicit val errorsShow: Show[Errors] = 
  derived.semiauto.show(implicitly[Show[NonEmptyList[Error]]])

修改后效果

运行后会输出NonEmptyList官方Show实例的格式,比如类似:

Errors(errors = Error(code=1234, message=Could not process) :: Nil)

内容的提问来源于stack exchange,提问作者satyagraha

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.23 12:03:26