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

时间:2015-07-19 10:25:16

标签: scala scalaz

我在上下文中有一个函数,(在一个Maybe / Option中)我希望传递一个值并直接从上下文中获取返回值。

我们在Scala中举个例子:

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

当然,我可以做到

res0.map(_(5))

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

好的,我可以这样做:

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

但是我在我的代码中到处复制/粘贴这个(我有很多函数包含在Option中,或者最糟糕的是,在Either中......)。

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

res0.applyOrElse(5, ...)

这个“将概念中的函数应用于某个值并立即将结果从上下文中返回”的概念是否存在于具有特定名称的FP中(我在所有Functor,Monad和Applicatives中都丢失了...... )?

3 个答案:

答案 0 :(得分:2)

您可以使用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

更一般地说,正如我上面提到的,这看起来有点像unliftId Kleisli,它采用包装函数A => F[B]并使用comonad实例折叠FF。如果您希望某些内容适用于OptionEither[E, ?]等,那么您可以编写类似于Optional实例F和默认值的内容。< / p>

答案 1 :(得分:1)

您可以使用applyOrElse撰写Option.fold之类的内容。

  

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最近的answer,我能够将以下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

答案 2 :(得分:0)

getOrElse是最合理的方式。关于将它复制/粘贴到任何地方 - 您可能不会以最佳方式划分逻辑。通常,您希望推迟在代码中解析您的选项(或期货/等),直到您需要解开它为止。在这种情况下,你的函数接受一个I​​nt并返回一个Int似乎更合理,你可以将你的选项映射到需要该函数结果的位置。

相关问题