如何改进使用 'Free monad' 的方法的代码?

How to improve the code of a method which uses 'Free monad'?

我正在尝试一些检查 this slides about Free Monad in Scala 的代码,并用一些稍微更改的代码制作了一个小项目。

项目在这里:https://github.com/freewind/free-the-monads

一开始一切似乎都很好,code is clean and beautiful:

def insertAndGet() = for {
    _ <- Script.insert("name", "Freewind")
    value <- Script.get("name")
  } yield value

  def insertAndDelete() = for {
    _ <- Script.insert("name", "Freewind")
    _ <- Script.delete("name")
    value <- Script.get("name")
  } yield value

  def insertAndUpdateAndDelete() = for {
    _ <- Script.insert("name", "Freewind1")
    oriValue <- Script.update("name", "Freewind2")
    _ <- Script.delete("name")
    finalValue <- Script.get("name")
  } yield (oriValue, finalValue)

但是当我的逻辑很复杂时,例如有一些 Script[Option[_]],我需要检查选项值来决定做某事,我不能再使用 for-comprehensionthe code is like

private def isLongName(name: String): Script[Boolean] = for {
  size <- Script.getLongNameConfig
} yield size.exists(name.length > _)

def upcaseLongName(key: String): Script[Option[String]] = {
  Script.get(key) flatMap {
    case Some(n) => for {
      isLong <- isLongName(n)
    } yield isLong match {
        case true => Some(n.toUpperCase)
        case false => Some(n)
      }
    case _ => Script.pure(None)
  }
}

我发现 Free Monad 方法真的很有趣也很酷,但我对 scalaz 不熟悉,刚开始学习 Monad 东西,不知道如何改进它。

有什么办法可以改善吗?


PS:您可以直接克隆项目https://github.com/freewind/free-the-monads并自己尝试

这是 OptionT monad 转换器的一个很好的用例:

import scalaz.OptionT, scalaz.syntax.monad._

def upcaseLongName(key: String): OptionT[Script, String] = for {
  n <- OptionT.optionT(Script.get(key))
  isLong <- isLongName(n).liftM[OptionT]
} yield if (isLong) n.toUpperCase else n 

此处 OptionT.optionTScript[Option[String]] 转换为 OptionT[Script, String].liftM[OptionT]Script[Boolean] 提升为相同的 monad。

现在改为:

println(upcaseLongName("name1").runWith(interpreter))

你会这样写:

println(upcaseLongName("name1").run.runWith(interpreter))

您也可以直接通过调用 run 来获得 upcaseLongName return 和 Script[Option[String]],但是如果有任何机会,您需要将其与其他组合option-y script-y things 最好有它 return OptionT[Script, String].