有没有更优雅的方式使用Scalaz写这个?

时间:2012-09-07 02:38:24

标签: scala scalaz

下面的代码有效但选项b上的模式匹配看起来并不优雅。 有没有办法在保持相同的语义的同时避免它?

object A {
  def apply(b: B): ValidationNEL[String, A] = ...
}

case class C(i: Int, a: Option[A])

object C {
  def apply(i: Int, b: Option[B]): ValidationNEL[String, C] = b match {
    case None => Success(C(i, None))
    case Some(sb) => A(sb).map(bb => C(i, Some(bb)))
  }     
}

2 个答案:

答案 0 :(得分:4)

使用scalaz,您可以折叠选项

b fold ( sb => A(sb) map (bb => C(i, some(bb))), C(i, none).success)

可能有一种方法可以使用 pointfree样式简化sb => A(sb) map (bb => C(i, some(bb))),但这在scala中通常很难看:

设置

scala> :paste
// Entering paste mode (ctrl-D to finish)

object A {
  def apply(b: B): ValidationNEL[String, A] = sys.error("")
}
case class A()
case class B()
case class C(i: Int, a: Option[A])

// Exiting paste mode, now interpreting.

defined module A
defined class A
defined class B
defined class C

First impl

scala> def apply(i: Int, b: Option[B]): ValidationNEL[String, C] =
     | b fold ( sb => A(sb) map (bb => C(i, some(bb))), C(i, none).success)
apply: (i: Int, b: Option[B])scalaz.Scalaz.ValidationNEL[String,C]

Second Impl

如果你宣布一流的功能,你就有更好的合成机会。例如:

object A { val fromB: B => ValidationNEL[String, A] = _ => sys.error("") }
object C { val fromA: Int => A => C = i => a => C(i, some(a)) }

defined module A
defined module C

然后

scala> def apply(i: Int, b: Option[B]): ValidationNEL[String, C] =
     | b fold (A.fromB andThen (_ map C.fromA(i)), C(i, none).success)
apply: (i: Int, b: Option[B])scalaz.Scalaz.ValidationNEL[String,C]

答案 1 :(得分:0)

您甚至不需要scalaz特定的东西来简化这一点,只需使用Option.map

b.map { sb => /* will only be called if b is Some[A] */ }.getOrElse { /* will only be called if b is None */ }

我无法向您提供确切的解决方案,因为您发布的代码不完整。 A中的case class C不在范围内。这应该是类型参数,还是属于class A的<{1}}?