【问题标题】:Pattern for mapping with identity and applying a side-effect使用身份进行映射并应用副作用的模式
【发布时间】:2018-07-17 05:14:50
【问题描述】:
下面的模式有没有更清晰的表达方式:
def getUser(id: String): Option[User] = ???
getUser("12345").map { user =>
someSideEffect(user)
user
}
注意给定一个仿函数,我们如何将其与恒等函数进行映射,同时将副作用函数应用于装箱值。
Future.andThen 正是这样做的:
将副作用函数应用于这个未来的结果,并且
用这个未来的结果返回一个新的未来。
是否有类似Future.andThen 但在一般情况下适用于任何函子的东西?
【问题讨论】:
标签:
scala
monads
side-effects
【解决方案1】:
没有开箱即用的东西。人们经常用这样的方式添加它:
object ImplicitUtils {
implicit class Utils[T](val t: T) extends AnyVal {
def tap(f: T => Unit): T = { f(t) ; t }
}
}
所以,现在你可以写:
import ImplicitUtils._
val user = getUser("foo").tap(someSideEffect)
【解决方案2】:
Scala 2.13 以tap 开箱即用地提供它
import scala.util.chaining._
Some(42) tap println
猫伴侣mouse 将其命名为<|
import mouse.all._
Some(42) <| println
两者都输出
Some(42)
res1: Some[Int] = Some(42)
在猫回购 Kestrel combinator for Monad/Functor #1559 和提供 flatTap 但不是 tap 中存在关于此主题的已关闭问题。
【解决方案3】:
object FunctorAndThen {
import cats.Functor
import cats.implicits._
import scala.language.higherKinds
implicit class AndThen[F[_], A](val f: F[A])(implicit ev: Functor[F]) {
def andThen(sideEffect: A => Unit): F[A] = {
f.map(sideEffect)
f
}
}
}
// Usage:
import FunctorAndThen._
import cats.implicits._
val result: Option[String] = Option("a").andThen(a => println(a))
println(result)