Scalaz技术问题:如何将EitherInstances与MonadError配合使用?
解决Scalaz MonadError与scala.util.Either的类型匹配问题
问题根源
你的代码出现类型错误,核心是对Scalaz MonadError的使用逻辑不符合它的设计规则:
- 直接传递
eitherMonad[String]给MonadError.apply的方式不对,MonadError.apply需要的是作用域内的隐式MonadError[F, S]实例,而非直接传入实例对象; - 让编译器自动推导时,要么是
Either对应的MonadError实例不在作用域,要么是类型构造器的表达不符合MonadError的要求(MonadError需要一元类型构造器F[_],而Either是二元的,需要用类型lambda转换)。
正确实现方案
首先先确认你的EitherInstances是正确的标准库Either的MonadError实例实现,示例如下:
import scalaz._ import scala.util.{Either => SEither} trait EitherInstances { implicit def eitherMonadError[E]: MonadError[({ type L[A] = SEither[E, A] })#L, E] = new MonadError[({ type L[A] = SEither[E, A] })#L, E] { override def point[A](a: => A): SEither[E, A] = SEither.Right(a) override def bind[A, B](fa: SEither[E, A])(f: A => SEither[E, B]): SEither[E, B] = fa.flatMap(f) override def handleError[A](fa: SEither[E, A])(f: E => SEither[E, A]): SEither[E, A] = fa.left.flatMap(f) override def raiseError[A](e: E): SEither[E, A] = SEither.Left(e) } }
这里用({ type L[A] = SEither[E, A] })#L这种类型lambda,把二元的Either[E, A]转换成MonadError需要的一元类型构造器F[_]。
接下来提供两种符合Scalaz惯用写法的解决方案:
方式1:用Scalaz语法糖直接调用(推荐)
Scalaz提供了隐式转换,可以让Either实例直接调用handleError方法,只要实例在作用域内:
object Foo extends EitherInstances { import scalaz.Scalaz._ import scala.util.{Either => SEither} private val success: SEither[String, Int] = SEither.Right(42) def main(args: Array[String]): Unit = { // 直接在Either实例上调用handleError val result = success.handleError(_ => SEither.Right(43)) println(result) // 输出Right(42),原实例是成功态;若为Left则会执行错误处理逻辑 } }
方式2:显式获取隐式实例调用
如果你想通过MonadError对象来调用,需要先让编译器找到隐式实例,再指定正确的类型构造器:
object Foo extends EitherInstances { import scalaz._ import scala.util.{Either => SEither} private val success: SEither[String, Int] = SEither.Right(42) def main(args: Array[String]): Unit = { // 显式引入隐式实例 implicit val me = eitherMonadError[String] // 指定类型构造器后调用handleError val result = MonadError[({ type L[A] = SEither[String, A] })#L, String] .handleError(success)(_ => SEither.Right(43)) println(result) } }
关键注意点
- 一定要用类型lambda处理
Either的二元类型,转换成MonadError要求的一元类型构造器; - 确保
EitherInstances中的MonadError核心方法(handleError、raiseError等)实现正确; - 优先使用第一种语法糖写法,代码更简洁也更符合Scalaz的社区惯用风格。
内容的提问来源于stack exchange,提问作者Gal
相关产品推荐
相关产品推荐

