如果定义了选项,则用于在链中应用函数的惯用Scala

Seb*_* N. 7 monads coding-style scala optional-parameters named-parameters

是否有预先存在/ 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
Run Code Online (Sandbox Code Playgroud)

我的applyOrBypass可以像这样定义:

def applyOrBypass[A, B](target: A, optValueToApply: Option[B], func: (A, B) => A) = {
  optValueToApply map { valueToApply =>
    func(target, valueToApply)
  } getOrElse {
    target
  }
}
Run Code Online (Sandbox Code Playgroud)

基本上我想要应用操作,具体取决于是否定义了某些选项值.如果不是,我应该得到预先存在的价值.理想情况下,我想链接这些操作,而不必使用var.

我的直觉告诉我,折叠或减少会涉及到,但我不确定它是如何工作的.或者也许有另一种方法与monadic-fors ...

任何建议/提示赞赏!

amn*_*mnn 9

Scala有一种方法可以用于理解(do如果你熟悉它,语法类似于haskell的表示法):

(for( v <- optValueToApply ) 
  yield func(target, v)).getOrElse(target)
Run Code Online (Sandbox Code Playgroud)

当然,如果您要检查是否存在以下几个变量,这会更有用:

(for( v1 <- optV1
    ; v2 <- optV2
    ; v3 <- optV3
    ) yield func(target, v1, v2, v3)).getOrElse(target)
Run Code Online (Sandbox Code Playgroud)

如果你试图在一个选项列表上积累一个值,那么我会推荐一个折叠,所以你的可选总和将如下所示:

val vs = List(Some(1), None, None, Some(2), Some(3))

(target /: vs) ( (x, v) => x + v.getOrElse(0) )
  // => 6 + target
Run Code Online (Sandbox Code Playgroud)

在您的操作func具有某些标识值的情况下,您可以对此进行概括identity:

(target /: vs) ( (x, v) => func(x, v.getOrElse(identity)) )
Run Code Online (Sandbox Code Playgroud)

在数学上说这个条件是(func, identity)形成一个Monoid.但那是旁边的.实际效果是,无论何时None达到,应用funcx并将始终产生x,(None's被忽略,Some值被解开并正常应用),这就是你想要的.


Rob*_*een 3

在这种情况下我会做的是使用部分应用的函数和identity

def applyOrBypass[A, B](optValueToApply: Option[B], func: B => A => A): A => A =
  optValueToApply.map(func).getOrElse(identity)
Run Code Online (Sandbox Code Playgroud)

你可以像这样应用它:

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)
Run Code Online (Sandbox Code Playgroud)