让我假设我有两个monad F
和M
(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
会很酷。任何提示?
答案 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]))
如果合适,也应该有效。