执行并获取包含在上下文中的函数的 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
的通用实例。如果您想要对 Option
、Either[E, ?]
等通用的东西,您可以编写类似的东西,将 Optional
实例用于 F
和默认值。
我在上下文中有一个函数(在 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
的通用实例。如果您想要对 Option
、Either[E, ?]
等通用的东西,您可以编写类似的东西,将 Optional
实例用于 F
和默认值。