是否有预先存在的/ Scala-idiomatic /更好的方法来实现这一目标?
def sum(x: Int, y: Int) = x + y
var x = 10
x = applyOrBypass(target=x, optValueToApply=Some(22), sum)
x = applyOrBypass(target=x, optValueToApply=None, sum)
println(x) // will be 32
我的applyOrBypass可以像这样定义:
def applyOrBypass[A, B](target: A, optValueToApply: Option[B], func: (A, B) => A) = {
optValueToApply map { valueToApply =>
func(target, valueToApply)
} getOrElse {
target
}
}
基本上我想要应用操作,具体取决于是否定义了某些Option值。如果不是,我应该得到预先存在的价值。理想情况下,我想链接这些操作,而不必使用var。
我的直觉告诉我,折叠或减少会涉及到,但我不确定它是如何工作的。或者也许还有另一种与monadic-fors有关的方法......
任何建议/提示都赞赏!
答案 0 :(得分:9)
Scala有一种方法可以用于理解(如果你熟悉它,语法类似于haskell的do
符号):
(for( v <- optValueToApply )
yield func(target, v)).getOrElse(target)
当然,如果您要检查是否存在以下几个变量,这会更有用:
(for( v1 <- optV1
; v2 <- optV2
; v3 <- optV3
) yield func(target, v1, v2, v3)).getOrElse(target)
如果您尝试在选项列表上累积值,那么我建议您使用折叠,因此您的可选总和将如下所示:
val vs = List(Some(1), None, None, Some(2), Some(3))
(target /: vs) ( (x, v) => x + v.getOrElse(0) )
// => 6 + target
如果您的操作func
具有某些标识值identity
,则可以对此进行概括:
(target /: vs) ( (x, v) => func(x, v.getOrElse(identity)) )
从数学上讲,这个条件是(func, identity)
形成 Monoid 。但那是旁边的。实际效果是,只要达到None
,将func
应用于x
并且x
将始终生成None
,Some
将被忽略,并且{{1}}值被解包并正常应用),这就是你想要的。
答案 1 :(得分:3)
在这种情况下我会做的是使用部分应用的函数和identity
:
def applyOrBypass[A, B](optValueToApply: Option[B], func: B => A => A): A => A =
optValueToApply.map(func).getOrElse(identity)
你会像这样申请:
def sum(x: Int)(y: Int) = x + y
var x = 10
x = applyOrBypass(optValueToApply=Some(22), sum)(x)
x = applyOrBypass(optValueToApply=None, sum)(x)
println(x)
答案 2 :(得分:2)
是的,您可以使用fold
。如果你有多个可选操作数,我相信Scalaz库中有一些有用的抽象。
var x = 10
x = Some(22).fold(x)(sum(_, x))
x = None .fold(x)(sum(_, x))
答案 3 :(得分:1)
如果您有多个功能,可以使用Scalaz完成。
有几种方法可以做到,但这是最简洁的方法之一。
首先,添加您的导入:
import scalaz._, Scalaz._
然后,创建你的函数(如果你的函数总是相同,这种方式是不值得的,但如果它们不同,那就有意义了)
val s = List(Some(22).map((i: Int) => (j: Int) => sum(i,j)),
None .map((i: Int) => (j: Int) => multiply(i,j)))
最后,全部应用它们:
(s.flatten.foldMap(Endo(_)))(x)