如何改进使用 '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-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并自己尝试
这是 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))
您也可以直接通过调用 run
来获得 upcaseLongName
return 和 Script[Option[String]]
,但是如果有任何机会,您需要将其与其他组合option-y script-y things 最好有它 return OptionT[Script, String]
.
我正在尝试一些检查 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并自己尝试
这是 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))
您也可以直接通过调用 run
来获得 upcaseLongName
return 和 Script[Option[String]]
,但是如果有任何机会,您需要将其与其他组合option-y script-y things 最好有它 return OptionT[Script, String]
.