使用哪个Monad变压器? [英] Which Monad Transformer to use?

查看:89
本文介绍了使用哪个Monad变压器?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试在下面编写validate函数,以便在遇到第一个错误后停止验证. three的返回类型不同于其他函数.我要使用哪个monad转换器才能编译此代码?

I am trying to write the validate function below so that the validation stops after the first error encountered. The return type of three is different to the other functions. Which monad transformer do I use in order to make this code compile?

import scalaz._
import Scalaz._
import scala.concurrent.Future
import scala.concurrent.ExecutionContext.Implicits.global


def one(a : String): Disjunction[Int, String] =
  a == "one" match {
    case true => \/-("one")
    case false => -\/(2)
  }

def two(a : String): Disjunction[Int, String] =
  a == "two" match {
    case true => \/-("two")
    case false => -\/(3)
  }

def three(a : String): Future[Disjunction[Int, String]] =
  Future (a == "three") map {
    case true => \/-("three")
    case false => -\/(4)
  }

def validate(a : String) = for {
  e1 <- one(a)
  e2 <- two(a)
  e3 <- EitherT(three(a))
} yield (e1 |+| e2 |+| e3)

编译错误:

Error:(27, 7) type mismatch;
 found   : scalaz.EitherT[scala.concurrent.Future,Int,String]
 required: scalaz.\/[?,?]
  e3 <- EitherT(three(a))
     ^
Error:(66, 7) type mismatch;
 found   : scalaz.EitherT[scala.concurrent.Future,Int,String]
 required: scalaz.\/[?,?]
  e3 <- EitherT(three(a))
     ^

推荐答案

在这种情况下,您可以采用两种一般方法.第一种是使所有方法返回您知道将要使用的堆栈(在本例中为EitherT[Future, Int, ?]),或者您可以让每个方法返回最准确地捕获其自身效果的类型,然后提高您在编写它们时会得到适当的值.

There are two general approaches you can take in a situation like this. The first is to make all your methods return the stack you know you'll be working with (in this case EitherT[Future, Int, ?]), or you can have each individual method return the type that most accurately captures its own effects, and then raise the values you get appropriately when you compose them.

如果您确切知道用​​法的用法,第一种方法可以使用法在语法上更加方便,但是后一种方法更灵活,我认为通常是更好的选择.在您的情况下,它看起来像这样:

The first approach can make usage more syntactically convenient if you know exactly what that usage is going to look like, but the latter approach is more flexible, and in my opinion generally the better choice. In your case it'd look something like this:

import scalaz._, Scalaz._
import scala.concurrent.Future
import scala.concurrent.ExecutionContext.Implicits.global

def one(a: String): Disjunction[Int, String] = (a == "one").either("one").or(2)
def two(a: String): Disjunction[Int, String] = (a == "two").either("two").or(3)

def three(a: String): EitherT[Future, Int, String] = EitherT(
  Future(a == "three").map(_.either("three").or(4))
)

def validate(a: String) = for {
  e1 <- EitherT.fromDisjunction[Future](one(a))
  e2 <- EitherT.fromDisjunction[Future](two(a))
  e3 <- three(a)
} yield (e1 |+| e2 |+| e3)

然后:

scala> validate("one").run.foreach(println)
-\/(3)

scala> validate("x").run.foreach(println)
-\/(2)

如果出于某种原因您想在for理解中使用一个普通的Future,则可以使用.liftM[EitherT[?[_], String, ?]]将其提升到EitherT[Future, String, A]中.

If for some reason you had a plain old Future that you wanted to use in the for-comprehension, you could lift it into the EitherT[Future, String, A] with .liftM[EitherT[?[_], String, ?]].

(请注意,此方法可能不会非常有用,因为它永远不会成功(字符串不能同时等于"one""two""three"),但是在至少可以解决这个问题.)

(Note that this method probably isn't terribly useful, since it'll never succeed (a string can't be equal to "one", "two", and "three" at the same time), but at least the composition works out.)

关于如何更一般地选择monad转换器堆栈:您只需将里面的类型翻过来,以使Future[Disjunction[Int, ?]]变为EitherT[Future, Int, ?],依此类推.在这种情况下,Future没有monad转换器(它是不可遍历,并且不可能在没有阻塞的情况下实现FutureT),因此无论如何,它都必须放在内部.

About how to pick the monad transformer stack more generally: you just turn the types inside out, so that Future[Disjunction[Int, ?]] becomes EitherT[Future, Int, ?], etc. In this case specifically, Future does not have a monad transformer (it's not traversable and it's impossible to implement FutureT without blocking), so you know it has to go on the inside, anyway.

这篇关于使用哪个Monad变压器?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆