Scala simplify nested monads

≡放荡痞女 提交于 2019-12-24 02:32:33

问题


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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!