2

我有一些用 Lift 编写的代码。基本上它的嵌套框(类似于选项的单子)。如果可能的话,我想把它简化一点。最好添加类型参数,以便在需要时可以轻松地将其更改为字符串或双精度。这是代码

tryo(r.param("boolean parameter").map(_.toBoolean)).map(_.openOr(false)).openOr(false)

如果发生异常并且 r 是 Req 对象,“tryo”是用于在 Box 中捕获和包装结果的辅助函数。“param”函数返回 Box[String](来自请求参数)。我想让它适用于 Int 的 String 等,如果可能的话,摆脱嵌套的 map/openOr (getOrElse 在你认为在 Option 类型中)。

单子变压器?

4

3 回答 3

6

flatMap那个狗屎!

r.param("boolean parameter").flatMap(tryo(_.toBoolean)).openOr(false)

或者,使用 for 理解:

val result = for {
  param <- r.param("boolean parameter")
  bool <- tryo(param.toBoolean)
} yield bool
result openOr false

但这并不能解决您获得不同类型的能力。为此,我建议如下:

def asOrDefault[T](input: Box[Any])(default: => T): T = input.flatMap(tryo(_.asInstanceOf[T])).openOr(default)

asOrDefault(r.param("any param"))(0)

这是未经测试的......另请注意,这scala.util.control.Exception.allCatch.opt()将返回aOption就像tryo返回 a一样Box

于 2012-08-20T13:52:13.797 回答
3

如果要抽象类型,则需要同时抽象默认值和字符串的转换:

case class Converter[T]( default: T, fromString: String => T )

然后为您的类型定义隐式实例:

implicit val intConverter = Converter[Int]( 0, _.toInt )
implicit val boolConverter = Converter[Boolean]( false, _.toBoolean )

最后,使用 pr1001 答案,使用隐式提供的转换器值:

def asOrDefault[T](input: Box[String])(implicit conv: Converter[T]): T = input.flatMap(
  s => tryo( conv.fromString(s))).openOr(conv.default)

编译器将为您选择适当的转换器实例:

asOrDefault[Int]( input.param("some int param") )
asOrDefault[Boolean]( input.param("some boolean param") )
于 2012-08-20T15:09:22.897 回答
0

我在@pr1001 和@paradigmatic 基础上构建的稍微调整的版本。

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)

在我的情况下使用:

def prettyPrint(implicit r: Req) = asOrDefault(r.param("prettyPrint"), false)

def maxResults(implicit r: Req): Int = asOrDefault(r.param("maxResults"), 20)
于 2012-08-21T14:10:07.263 回答