执行并获取包含在上下文中的函数的 return 值?

Executing and getting return value of a function wrapped in a context?

我在上下文中有一个函数(在 Maybe / Option 中),我想向它传递一个值并直接从上下文中取回 return 值。

让我们以 Scala 为例:

scala> Some((x:Int) => x * x)
res0: Some[Int => Int] = Some(<function1>)

当然可以

res0.map(_(5))

执行函数,但结果包装在上下文中。

好的,我可以做到:

res0.map(_(5)).getOrElse(...)

但我的代码中到处都是 copy/pasting 这个(我有很多函数包装在 Option 中,或者最糟糕的是,在 Either 中...)。

我需要一个更好的形式,例如:

res0.applyOrElse(5, ...)

'applying a function in a concept to a value and immediatly returning the result out of the context' 这个概念是否存在于具有特定名称的 FP 中(我迷失在所有那些 Functor、Monad 和 Applicatives 中...)?

getOrElse 是最合乎逻辑的方法。关于 copy/pasting 它无处不在 - 你可能没有以最佳方式划分你的逻辑。通常,您希望推迟解析代码中的选项(或 Futures/etc),直到您需要将其解包。在这种情况下,您的函数接受一个 Int 和 returns 一个 Int 似乎更明智,然后将您的选项映射到您需要该函数结果的位置。

您可以使用 Option.fold 编写类似 applyOrElse 的内容。

fold[B](ifEmpty: ⇒ B)(f: (A) ⇒ B): B

val squared = Some((x:Int) => x * x)
squared.fold { 
  // or else = ifEmpty
  math.pow(5, 2).toInt
}{
  // execute function
  _(5)
}

使用 Travis Browns 最近 在另一个问题上,我能够拼凑出以下 applyOrElse 函数。它取决于 Shapeless,您需要将参数作为 HList 传递,因此它可能不是您想要的。

def applyOrElse[F, I <: HList, O](
  optionFun: Option[F],
  input: I,
  orElse: => O
)(implicit
  ftp: FnToProduct.Aux[F, I => O]
): O = optionFun.fold(orElse)(f => ftp(f)(input))

可以用作:

val squared = Some((x:Int) => x * x)
applyOrElse(squared, 2 :: HNil, 10)
// res0: Int = 4

applyOrElse(None, 2 :: HNil, 10)
// res1: Int = 10

val concat = Some((a: String, b: String) => s"$a $b")
applyOrElse(concat, "hello" :: "world" :: HNil, "not" + "executed")
// res2: String = hello world

您可以使用andThen将默认值从您调用函数的地方移动到您定义它的地方:

val foo: String => Option[Int] = s => Some(s.size)
val bar: String => Int = foo.andThen(_.getOrElse(100))

这仅适用于 Function1,但如果您想要更通用的版本,Scalaz 为 FunctionN:

提供了函子实例
import scalaz._, Scalaz._

val foo: (String, Int) => Option[Int] = (s, i) => Some(s.size + i)
val bar: (String, Int) => Int = foo.map(_.getOrElse(100))

这也适用于 Function1——只需将上面的 andThen 替换为 map

更一般地说,正如我上面提到的,这看起来有点像 Kleisli 上的 unliftId,它采用包装函数 A => F[B] 并使用F 的通用实例。如果您想要对 OptionEither[E, ?] 等通用的东西,您可以编写类似的东西,将 Optional 实例用于 F 和默认值。