我正在尝试一些检查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-comprehension
,the 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并亲自尝试
答案 0 :(得分:6)
这是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.optionT
将Script[Option[String]]
转换为OptionT[Script, String]
,.liftM[OptionT]
将Script[Boolean]
转换为同一个monad。
现在而不是:
println(upcaseLongName("name1").runWith(interpreter))
你写的是:
println(upcaseLongName("name1").run.runWith(interpreter))
你也可以upcaseLongName
直接通过调用Script[Option[String]]
返回run
,但是如果有任何机会你需要用其他选项-y脚本编写它 - y事情最好让它返回OptionT[Script, String]
。