Last active
August 19, 2019 18:05
-
-
Save taisukeoe/5b81778e582bc61f9a27a0863a1a2670 to your computer and use it in GitHub Desktop.
MonadErrorのコレクションに対し、Error値を蓄積しながらsequenceする(Applicative合成する)方法
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import cats. | |
import cats.implicits._ | |
case class MyError(errorMsg: String) | |
object MyError { | |
implicit val s: Semigroup[MyError] = new cats.kernel.Semigroup[MyError] { | |
override def combine(t1: MyError, t2: MyError): MyError = MyError(t1.errorMsg + "\n" + t2.errorMsg) | |
} | |
} | |
val a: Either[MyError, String] = MyError("boom!").asLeft | |
val b: Either[MyError, String] = MyError("ouch!").asLeft | |
val list = List(a, b) | |
list.sequence | |
// catsEitherのApplicative合成(ap)はfail fast。最初のエラー値と共に失敗する。 | |
// Left(MyError(boom!)) | |
// このエラー値を蓄積する方法はないだろうか? |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
//ValidatedのApplicative.apの実装は、Semigroup.combineを利用して蓄積することを利用する | |
def meSequenceG[T[_]: Traverse, F[_], E: Semigroup, A](l: T[F[A]])(implicit ME: MonadError[F, E]): F[T[A]] = | |
ME.rethrow(l.traverse(_.attempt.map(_.toValidated)).map(_.sequence.toEither)) | |
println(meSequenceG(list)) | |
// Left(MyError(boom! | |
// ouch!)) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
//ValidatedのApplicative.apの実装と同様に、Error値を蓄積するEitherのApplicativeインスタンスを定義する | |
object AccumulativeEither { | |
def applicative[E](implicit S: Semigroup[E]): Applicative[({ type λ[AA] = Either[E, AA]})#λ] = new Applicative[({ | |
type λ[A] = Either[E, A] | |
})#λ] { | |
override def pure[A](x: A): Either[E, A] = x.asRight | |
override def ap[A, B](ff: Either[E, A => B])(fa: Either[E, A]): Either[E, B] = (fa, ff) match { | |
case (Right(a), Right(f)) => f(a).asRight | |
case (Left(e1), Left(e2)) => S.combine(e2, e1).asLeft | |
case (Left(e), _) => e.asLeft | |
case (_, Left(e)) => e.asLeft | |
} | |
} | |
} | |
def meSequenceE[T[_], F[_], E, A](l: T[F[A]])(implicit ME: MonadError[F, E], S: Semigroup[E], TR: Traverse[T]): F[T[A]] = | |
ME.rethrow(l.traverse(_.attempt).map(TR.sequence(_)(AccumulativeEither.applicative))) | |
println(meSequenceE(list)) | |
// Left(MyError(boom! | |
// ouch!)) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment