Scala 围绕更高种类的类型展开一个选项,寻找一种更惯用的方法

Scala flattening an Option around a higher kinded type, looking for a more idiomatic approach

给定更高的 Kinded 类型 M 和 monad 类型 class,我可以通过 for-comprehension 对 M 中的值进行操作。使用 return 选项的函数,我正在寻找一种比我现有的解决方案更合适的方法来展平这些选项。如下

class Test[M[+_]:Monad](calc:Calculator[M]) {
  import Monad._

  def doSomething(x:Float):M[Option[Float]] = {
    for {
      y:Option[Float] <- calc.divideBy(x)   // divideBy returns M[Option[Float]]
      z:Option[Float] <- y.fold[M[Option[Float]]](implicitly[Monad[M]].point(None))(i => calc.divideBy(i))
    }  yield z
  }
} 

所以我要更正以下内容:

y.fold[M[Option[Float]]](implicitly[Monad[M]].point(None))(i => calc.divideBy(i))

还有这种情况,我没有调用第二个 divideBy,而是调用 multiplyBy which returns M[Float]

y.fold[M[Option[Float]]](implicitly[Monad[M]].point(None))(i => calc.multipleBy(i).map(Some(_)) 

也许这就是 Monad Transformers 的情况,但我不确定该怎么做。

似乎 monad 转换器可以在这方面为您提供帮助。例如,以下编译,我认为大致符合您的要求:

import scalaz._, Scalaz._

abstract class Calculator[M[_]: Monad] {
  def divideBy(x: Float): M[Option[Float]]
  def multiplyBy(x: Float): M[Float]
}

class Test[M[_]: Monad](calc: Calculator[M]) {
  def doSomething(x: Float): OptionT[M, Float] = for {
    y <- OptionT(calc.divideBy(x))
    z <- calc.multiplyBy(y).liftM[OptionT]
  } yield z
}

现在 doSomething returns 一个 OptionT[M, Float],它是 M[Option[Float]] 的一种包装器,允许您使用 [=14] 中的所有内容=] 一元化。要从 OptionT[M, Float] 取回 M[Option[Float]],您可以使用 run 方法。