【问题标题】:Lift full types into monad transformers将完整类型提升为单子变压器
【发布时间】:2018-12-20 03:38:39
【问题描述】:

我有这 3 个单子转换器

type T[A] = OptionT[Future, A]
type E[A] = EitherT[Future, String, A]
type P[A] = OptionT[E, A]

我想将相应的完整类型(即完全对应的类型)提升到这些类型中。所以对于 T,我想将 Future[Option[Int]] 提升到其中。对于E,我想提升Future(Either[String, Int]),对于P,我想提升(Future[Either[String, Option[Int]]])。

我编写了这段代码,它可以编译。除了我需要一种更简洁的方法来实现同样的目标。

val x : T[Int] = OptionT(Future(Option(10)))
val y : E[Int] = EitherT(Future(Right(10).asInstanceOf[Either[String, Int]]))
val z : P[Int] = OptionT(EitherT(Future(Right(Option(10)).asInstanceOf[Either[String, Option[Int]]])))

我正在使用 Cats 1.1.0 和 Scala 2.12.3。

asInstanceOf 的事情很烦人。但是如果我将最后一行更改为

val z : P[Int] = OptionT(EitherT(Future(Right(Option(10)))))

我得到这个编译器错误

[info] Compiling 1 Scala source to 
[error] /Users//code/dallasscalacats/src/main/scala/com//Transformers.scala:32: no type parameters for method apply: (value: F[Either[A,B]])cats.data.EitherT[F,A,B] in object EitherT exist so that it can be applied to arguments (scala.concurrent.Future[scala.util.Right[Nothing,Option[Int]]])
[error]  --- because ---
[error] argument expression's type is not compatible with formal parameter type;
[error]  found   : scala.concurrent.Future[scala.util.Right[Nothing,Option[Int]]]
[error]  required: ?F[Either[?A,?B]]
[error]     val z : P[Int] = OptionT(EitherT(Future(Right(Option(10)))))
[error]                              ^
[error] /Users//code/dallasscalacats/src/main/scala/com//Transformers.scala:32: type mismatch;
[error]  found   : scala.concurrent.Future[scala.util.Right[Nothing,Option[Int]]]
[error]  required: F[Either[A,B]]
[error]     val z : P[Int] = OptionT(EitherT(Future(Right(Option(10)))))
[error]                                            ^
[error] /Users//code/dallasscalacats/src/main/scala/com//Transformers.scala:32: type mismatch;
[error]  found   : cats.data.EitherT[F,A,B]
[error]  required: com.abhi.Transformers.E[Option[Int]]
[error]     (which expands to)  cats.data.EitherT[scala.concurrent.Future,String,Option[Int]]
[error]     val z : P[Int] = OptionT(EitherT(Future(Right(Option(10)))))
[error]                                     ^
[error] three errors found
[error] (compile:compileIncremental) Compilation failed
[error] Total time: 0 s, completed Jul 11, 2018 9:46:21 PM
>

【问题讨论】:

    标签: scala monad-transformers scala-cats


    【解决方案1】:

    尝试为 Right 提供类型参数:

    val z : P[Int] = OptionT(EitherT(Future(Right[String,Option[Int]](Option(10)))))
    

    没有类型参数,当你做Right(1) scala 推断Either[Nothing,Int]

    【讨论】:

    • 仍然很冗长。有没有更好的办法?
    【解决方案2】:

    你可以使用import cats.implicits._的implicits方法 然后你可以写类似的东西

    val z: P[Int] = OptionT(EitherT(Future(10.some.asRight[String])))
    

    当然,您也可以编写自己的隐式

    implicit class EitherFuture[A, B](val e: Future[A Either B]) extends AnyVal {
      def asEitherT: EitherT[Future, A, B] = EitherT(e)
    }
    
    implicit class OptionEitherT[A](val e: EitherT[Future, String, Option[A]]) extends AnyVal {
      def asOptionT = OptionT(e)
    }
    
    val zz: P[Int] = Future(10.some.asRight[String]).asEitherT.asOptionT
    

    【讨论】:

    • 非常酷!让我们看看是否还有更多答案。否则我很乐意标记这个。
    • 确保extend AnyVal 避免隐式类的额外包装分配。
    • @YuvalItzchakov 感谢您的评论。更新了答案
    • 我还有最后一个问题。一切正常。但如果我这样做 for {x <- Future(10.some.asRight[String]).asEitherT.asOptionT} yield {..} 我会收到错误 value foreach is not a member of cats.data.OptionT
    • @KnowsNotMuch 这有点离题了,foreach 相当于没有yieldfor 语句。我可以运行你粘贴的代码。所以检查你的实际代码的语法。
    猜你喜欢
    • 1970-01-01
    • 2012-02-21
    • 2014-08-03
    • 1970-01-01
    • 1970-01-01
    • 2011-11-16
    • 1970-01-01
    • 2018-07-25
    • 1970-01-01
    相关资源
    最近更新 更多