Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

K / Kestrel Combinator for monads?

implicit class KComb[A](a: A) {
  def K(f: A => Any): A = { f(a); a }
}

Given this implementation of the K combinator, we can chain method calls on a value while applying side effects, without the need for temp variables. E.g.:

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

Now, I need to do something similar, but using the IO monad instead.

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

My question is: does a combinator for this operation exist already? Is there anything in Scalaz, or maybe some other library, that does this?

I couldn't find anything, so I rolled out this variant of the K combinator for monads myself. I called it tapM because 1) the K combinator is called tap in Ruby and unsafeTap in Scalaz and 2) it seems Scalaz follows the pattern of appending M to monadic variants of well known methods (e.g. foldLeftM, foldMapM, ifM, untilM, whileM).

But I'd still like to know if anything of the sort exists already and I'm just reinventing the wheel.

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
like image 765
dcastro Avatar asked Oct 31 '22 17:10

dcastro


1 Answers

Edit: My initial answer was misguided. Here's the correct one.

There's a flatTap method on FlatMap in cats and >>! on BindOps in scalaz.

getDocument flatTap print >>= process

getDocument >>! print >>= process

Edit^2: Changed flatMap to >>= to more easily show the relationship between tap and bind.

like image 92
Mark Canlas Avatar answered Nov 04 '22 06:11

Mark Canlas