问题
I have some code written in Lift. Basically its nested Box (similar monad to Option). I'd like to simplify it a little bit if possible. Preferably add type parameter so this could be easily changed to string or double if needed. Here is the code
tryo(r.param("boolean parameter").map(_.toBoolean)).map(_.openOr(false)).openOr(false)
"tryo" is helper function to catch and wrap results in Box if exception occurs and r is Req object. "param" function returns Box[String] (that comes from request param). I'd like to make it working for Int's String's etc. and if possible get rid of nested map/openOr (getOrElse in you think in Option types).
Monad transformers ?
回答1:
flatMap
that sh*t!
r.param("boolean parameter").flatMap(tryo(_.toBoolean)).openOr(false)
Or, use a for comprehension:
val result = for {
param <- r.param("boolean parameter")
bool <- tryo(param.toBoolean)
} yield bool
result openOr false
But that doesn't solve your ability to get different types. For that I would suggest something like:
def asOrDefault[T](input: Box[Any])(default: => T): T = input.flatMap(tryo(_.asInstanceOf[T])).openOr(default)
asOrDefault(r.param("any param"))(0)
This is untested... Note also that scala.util.control.Exception.allCatch.opt()
will return an Option
just like tryo
returns a Box
.
回答2:
If you want to absract the type, you need to abstract both the default value, and the conversion from a string:
case class Converter[T]( default: T, fromString: String => T )
Then define implicit instances for your types:
implicit val intConverter = Converter[Int]( 0, _.toInt )
implicit val boolConverter = Converter[Boolean]( false, _.toBoolean )
Finally, use pr1001 answer, using an implicitly provided value of converter:
def asOrDefault[T](input: Box[String])(implicit conv: Converter[T]): T = input.flatMap(
s => tryo( conv.fromString(s))).openOr(conv.default)
The compiler will select the appropriate converter instance for you:
asOrDefault[Int]( input.param("some int param") )
asOrDefault[Boolean]( input.param("some boolean param") )
回答3:
My little bit tweaked version building on @pr1001 and @paradigmatic ground.
case class Converter[T]( fromString: String => T )
implicit val boolConverter = Converter(_.toBoolean)
implicit val intConverter = Converter(_.toInt)
def asOrDefault[T](input: Box[String], default: T)(implicit conv: Converter[T]): T =
input.flatMap( s => tryo(conv.fromString(s))).openOr(default)
And usage in my case:
def prettyPrint(implicit r: Req) = asOrDefault(r.param("prettyPrint"), false)
def maxResults(implicit r: Req): Int = asOrDefault(r.param("maxResults"), 20)
来源:https://stackoverflow.com/questions/12038772/scala-simplify-nested-monads