将所有过滤函数应用于一个值
Apply all filter functions to a value
我有一个看起来像这样的函数:
def createBuilder(builder: InitialBuilder, name: Option[String], useCache: Boolean, timeout: Option[Long]): Builder = {
val filters: List[Builder => Option[Builder]] = List(
b => name.map(b.withName),
b => if (useCache) Some(b.withCache) else None,
b => timeout.map(b.withTimeout))
filters.foldLeft(builder)((b,filter) => filter(b).getOrElse(b))
}
它从Builder => Option[Builder]
定义了3个过滤函数(从可选参数转换而来)。我想将它们应用于现有的 builder
值,因此在 None
的情况下,我可以 return 本身不变。
上面的代码是我能想到的最好的代码,但我觉得我应该能够以某种方式使用 Monoid 来做到这一点 - return identity
在 [= 的情况下26=].
不幸的是,我不知道如何定义一个有意义的。或者,如果有 better/different 方法可以做到这一点?
我正在使用猫,如果这很重要的话。有什么想法吗?
我认为您的 A => M[A]
结构有点多余。您在示例中使用的过滤器函数实际上等同于 Option[Builder => Builder]
。那是因为您没有使用他们的 Builder
参数来决定结果应该是 Some
还是 None
。您可以使用 .getOrElse(identity)
.
将函数进一步简化为 Builder => Builder
这里有 2 个使用这个想法的实现。他们甚至不真正依赖猫。
def createBuilder(
builder: InitialBuilder, name: Option[String], useCache: Boolean, timeout: Option[Long]
): Builder = {
def builderStage[T](param: Option[T])(modify: T => Builder => Builder): Builder => Builder =
param.fold(identity[Builder](_))(modify)
val stages: List[Builder => Builder] = List(
builderStage(name)(n => _ withName n),
// `Boolean` is equivalent to `Option[Unit]`, and we convert it to that representation
// Haskell has a special function to do such a conversion `guard`.
// In Scalaz you can use an extension method `useCache.option(())`.
// In cats a similar `option` is provided in Mouse library.
// But you can just write this manually or define your own extension
builderStage(if (useCache) ().some else none)(_ => _.withCache),
builderStage(timeout)(t => _ withTimeout t)
)
// It should be possible to use `foldK` method in cats, to do a similar thing.
// The problems are that it may be more esoteric and harder to understand,
// it seems you have to provide type arguments even with -Ypartial-unification,
// it folds starting from the last function, because it's based on `compose`.
// Anyway, `reduceLeft(_ andThen _)` works fine for a list of plain functions.
stages.reduceLeft(_ andThen _)(builder)
}
另一种可能性是 flatten
Option
的 List
,它只是简单地删除 None
而不会将它们强制转换为 identity
:
def createBuilder2(
builder: InitialBuilder, name: Option[String], useCache: Boolean, timeout: Option[Long]
): Builder = {
val stages: List[Option[Builder => Builder]] = List(
name.map(n => _ withName n),
if (useCache) Some(_.withCache) else None,
timeout.map(t => _ withTimeout t)
)
stages.flatten.reduceLeft(_ andThen _)(builder)
}
我有一个看起来像这样的函数:
def createBuilder(builder: InitialBuilder, name: Option[String], useCache: Boolean, timeout: Option[Long]): Builder = {
val filters: List[Builder => Option[Builder]] = List(
b => name.map(b.withName),
b => if (useCache) Some(b.withCache) else None,
b => timeout.map(b.withTimeout))
filters.foldLeft(builder)((b,filter) => filter(b).getOrElse(b))
}
它从Builder => Option[Builder]
定义了3个过滤函数(从可选参数转换而来)。我想将它们应用于现有的 builder
值,因此在 None
的情况下,我可以 return 本身不变。
上面的代码是我能想到的最好的代码,但我觉得我应该能够以某种方式使用 Monoid 来做到这一点 - return identity
在 [= 的情况下26=].
不幸的是,我不知道如何定义一个有意义的。或者,如果有 better/different 方法可以做到这一点?
我正在使用猫,如果这很重要的话。有什么想法吗?
我认为您的 A => M[A]
结构有点多余。您在示例中使用的过滤器函数实际上等同于 Option[Builder => Builder]
。那是因为您没有使用他们的 Builder
参数来决定结果应该是 Some
还是 None
。您可以使用 .getOrElse(identity)
.
Builder => Builder
这里有 2 个使用这个想法的实现。他们甚至不真正依赖猫。
def createBuilder(
builder: InitialBuilder, name: Option[String], useCache: Boolean, timeout: Option[Long]
): Builder = {
def builderStage[T](param: Option[T])(modify: T => Builder => Builder): Builder => Builder =
param.fold(identity[Builder](_))(modify)
val stages: List[Builder => Builder] = List(
builderStage(name)(n => _ withName n),
// `Boolean` is equivalent to `Option[Unit]`, and we convert it to that representation
// Haskell has a special function to do such a conversion `guard`.
// In Scalaz you can use an extension method `useCache.option(())`.
// In cats a similar `option` is provided in Mouse library.
// But you can just write this manually or define your own extension
builderStage(if (useCache) ().some else none)(_ => _.withCache),
builderStage(timeout)(t => _ withTimeout t)
)
// It should be possible to use `foldK` method in cats, to do a similar thing.
// The problems are that it may be more esoteric and harder to understand,
// it seems you have to provide type arguments even with -Ypartial-unification,
// it folds starting from the last function, because it's based on `compose`.
// Anyway, `reduceLeft(_ andThen _)` works fine for a list of plain functions.
stages.reduceLeft(_ andThen _)(builder)
}
另一种可能性是 flatten
Option
的 List
,它只是简单地删除 None
而不会将它们强制转换为 identity
:
def createBuilder2(
builder: InitialBuilder, name: Option[String], useCache: Boolean, timeout: Option[Long]
): Builder = {
val stages: List[Option[Builder => Builder]] = List(
name.map(n => _ withName n),
if (useCache) Some(_.withCache) else None,
timeout.map(t => _ withTimeout t)
)
stages.flatten.reduceLeft(_ andThen _)(builder)
}