0
votes

let's suppose I have two monads F and M (Scalaz-style) and a function f: A => F[B]. I'd like to create a function g: A => F[M[B]] that applies f first then binds F monad with pure[M]. An example for clarity's sake:

// here, F = Option and M = List
import scalaz.syntax.monad._
import scalaz.std.list._

def f(x: Int): Option[Int] = Some(x)
def g(x: Int): Option[List[Int]] = f(x).map(t => List(t))

Here, implementation of g is using the inner monad (List) constructor explicitly. I could avoid that as follows:

def g2[M[_]: Monad](x: Int): Option[M[Int]] = f(x).map(_.pure[M])

Now, the question is: I have a function that expects something like g (so a function value of Int => Option[List[Int]]) and something like f in my hands. How do I feed one to another? To put it plainly:

def f(x: Int): Option[Int] = ...
def callMe(h: (Int => Option[List[Int]]) = ...
//I can of course do that:
callMe(t => f(t).map(_.point[List]))

//How it without lambda expression?
callMe(f.kindOfALift[List]???)
callMe(f andThen ???)

The problem here can be of course abstracted to support not only Int => Option[Int] but A => M[B] in general, but that's the easy part. The hard part (for me) is wrapping the result into an inner monad. The next step is to make it work on transformed monads (so instead of having a monad M it'll be cool to get it work with MT monad transformer). Any hints?

1

1 Answers

0
votes

Just change g2 to take f as the argument:

def g2[A, B, M1[_]: Monad, M2[_]: Monad](f: A => M1[B]): A => M1[M2[B]] = 
  x => f(x).map(_.pure[M2])

Except this is going to have problems with type inference, since you generally need to specify M2 and there is no way to tell Scala to infer only some type arguments. But it's easily fixable:

implicit class FOp[A, B, M1[_]: Monad](f: A => M1[B]): A => M1[M2[B]] {
  def kindOfALift[M2[_]: Monad] = x => f(x).map(_.pure[M2])
}

callMe(f andThen ???)

f.andThen(_.map(_.point[List])) should also work if that's suitable.