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

Fre*_*ind 1 monads refactoring functional-programming scala scalaz

我正在尝试一些代码来检查Scala中的这些幻灯片Free Monad,并用一些稍微改变的代码创建了一个小项目.

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

一开始看起来一切都很好,代码干净漂亮:

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)
Run Code Online (Sandbox Code Playgroud)

但是当我的逻辑很复杂时,例如有一些Script[Option[_]],我需要检查选项值以决定做某事,我不能再使用了for-comprehension,代码如下:

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)
  }
}
Run Code Online (Sandbox Code Playgroud)

我发现这种Free Monad方法真的很有趣而且很酷,但我不熟悉scalaz,只是开始学习Monad东西,不知道如何改进它.

有没有办法让它变得更好?


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

Tra*_*own 6

这是OptionTmonad变换器的一个很好的用例:

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 
Run Code Online (Sandbox Code Playgroud)

这里OptionT.optionT将a转换Script[Option[String]]为a OptionT[Script, String],并将.liftM[OptionT]a Script[Boolean]引入同一monad.

而不是这个:

println(upcaseLongName("name1").runWith(interpreter))
Run Code Online (Sandbox Code Playgroud)

你写这个:

println(upcaseLongName("name1").run.runWith(interpreter))
Run Code Online (Sandbox Code Playgroud)

您也可以直接通过调用upcaseLongName返回,但是如果有任何机会您需要使用其他选项-y脚本组合它,那么最好让它返回.Script[Option[String]]runOptionT[Script, String]