用于单子的 K/Kestrel 组合器?

dca*_*tro 5 monads functional-programming scala combinators higher-order-functions

implicit class KComb[A](a: A) {
  def K(f: A => Any): A = { f(a); a }
}
Run Code Online (Sandbox Code Playgroud)

鉴于 K 组合器的这种实现,我们可以在应用副作用的同时链接一个值的方法调用,而无需临时变量。例如:

case class Document()
case class Result()

def getDocument: Document = ???
def print(d: Document): Unit = ???
def process(d: Document): Result = ???

val result = process(getDocument.K(print))
// Or, using the thrush combinator
// val result = getDocument |> (_.K(print)) |> process
Run Code Online (Sandbox Code Playgroud)

现在,我需要做一些类似的事情,但改用 IO monad。

def getDocument: IO[Document] = ???
def print(d: Document): IO[Unit] = ???
def process(d: Document): IO[Result] = ???
Run Code Online (Sandbox Code Playgroud)

我的问题是:此操作的组合器是否已经存在?Scalaz 或其他一些库中是否有任何东西可以做到这一点?

我找不到任何东西,所以我K自己为 monad推出了这个组合器的变体。我tapM之所以这样称呼它,是因为 1)tap在 Ruby 和unsafeTapScalaz 中调用了 K 组合器,以及 2) Scalaz 似乎遵循了附加M到众所周知的方法的monadic变体(例如foldLeftM, foldMapM, ifM, untilM, whileM)的模式。

但我仍然想知道是否已经存在类似的东西,我只是在重新发明轮子。

implicit class KMonad[M[_]: Monad, A](ma: M[A]) {

  def tapM[B](f: A => M[B]): M[A] =
    for {
      a <- ma
      _ <- f(a)
    } yield a
}

// usage
getDocument tapM print flatMap process
Run Code Online (Sandbox Code Playgroud)

Mar*_*las 2

编辑:我最初的答案被误导了。这是正确的。

在 cats 和scalaz中都有flatTapon 方法。FlatMap>>!BindOps

getDocument flatTap print >>= process

getDocument >>! print >>= process
Run Code Online (Sandbox Code Playgroud)

编辑^2:更改flatMap>>=更容易显示点击和绑定之间的关系。