将monadic函数转换为另一个monad中的返回点

时间:2015-09-29 13:01:09

标签: scala scalaz monad-transformers

让我假设我有两个monad FM(Scalaz风格)和一个函数f: A => F[B]。我想创建一个函数g: A => F[M[B]],首先应用f然后将F monad与pure[M]绑定。为清晰起见的一个例子:

// 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))

这里,g的实现明确使用内部monad(List)构造函数。我可以避免如下:

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

现在,问题是:我的函数需要g(所以函数值为Int => Option[List[Int]])和类似f之类的函数。我如何互相喂食?说白了:

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 ???)

这里的问题当然可以抽象化,不仅支持Int => Option[Int],而且支持A => M[B],但这很容易。困难的部分(对我来说)将结果包装成内部monad。下一步是让它适用于变换后的monad(因此,使用M monad变换器,而不是使用monad MT会很酷。任何提示?

1 个答案:

答案 0 :(得分:0)

只需更改g2即可将f作为参数:

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

除非这会导致类型推断出现问题,因为您通常需要指定M2,并且无法告诉Scala仅推断某些类型参数。但它很容易解决:

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]))如果合适,也应该有效。