基于Tagless Final风格优雅转换Either为Error的便捷方法问询
嘿,这个场景我太熟了!你现在手动用fold来处理Either转F的写法确实有点啰嗦,Cats Effect其实提供了更简洁的方式来帮你“unwrap”Either~
核心解决方案:用liftTo语法扩展
你想要的效果——把F[Either[E, A]]转换成F[A],Left时触发raiseError,Right时提取值——其实可以用cats.syntax.either._里的liftTo方法一键搞定。因为Sync继承了MonadError,而liftTo正好需要MonadError实例来处理错误抛出。
修改你的代码后会变成这样:
import cats.effect.Sync import cats.implicits._ import cats.syntax.either._ // 记得导入这个语法扩展 case class User(name: String) case object Error extends Exception def validate[F[_]: Sync](name: String): F[Either[Error, User]] = Sync[F].pure(User(name).asRight) def doSomething[F[_]: Sync]: F[User] = for { maybeUser <- validate("Name") user <- maybeUser.liftTo[F] // 这一行就替代了原来的fold逻辑! } yield user
额外优化:直接返回F[A](如果不需要保留Either)
如果你的validate方法不需要在纯代码场景复用Either返回值,还可以直接让它返回F[User],彻底省去后续的unwrap步骤:
def validate[F[_]: Sync](name: String): F[User] = // 模拟实际校验逻辑:如果name为空则抛出错误,否则返回User if (name.trim.isEmpty) Sync[F].raiseError(Error) else Sync[F].pure(User(name)) // 这样doSomething会更简洁 def doSomething[F[_]: Sync]: F[User] = validate("Name")
为什么liftTo好用?
liftTo本质上就是封装了你手动写的fold逻辑:它会自动将Left中的错误通过MonadError.raiseError抛出,将Right中的值通过MonadError.pure包装返回,完全符合你的需求,还让代码更简洁易读。
内容的提问来源于stack exchange,提问作者Stu Redman
相关产品推荐
相关产品推荐

