import scalaz.{Monad, Applicative, Apply, Bind}
import language.higherKinds
def extractF[A, B, F[_]: Monad](ff: F[A => F[B]]): A => F[B] =
(Applicative[F].pure[A] _).andThen(Apply[F].apF(ff)).andThen(Bind[F].join)(_)
import scalaz.std.list._
val f = extractF(List((x: Int) => List(x, x)))
f(3) // List(3, 3)
Applicative 的纯粹是引导链,将 A 提升到 F[A] 就像 Haskell 的回归一样。然后我们使用Applicative 的弱化变体Apply 中的apF 将参数替换为函子内的函数,从F[A] 和F[A => F[B]] 获得F[F[B]]。最后,从 Bind 类型类(monad 的第二个组件)连接,将 F[F[B]] 展平为 F[B]。剩下的就是在 A 的值上调用组合函数。注意 Monad 确实是 Applicative 和 Bind,Applicative 也是 Apply,所以可以用 Monad 替换所有细粒度类型类的使用。
虽然这样可行,但在某些情况下可能会因为语法怪癖而带来不便。用户被迫将 monad 的实例显式传递给从上下文绑定或将函数保存到 val 中生成的隐式参数,然后再将其应用于参数。等效功能是:
import scalaz.{Monad, Applicative, Apply, Bind}
import language.higherKinds
def extractF[A, B, F[_]: Monad](ff: F[A => F[B]])(a: A): F[B] =
(Applicative[F].pure[A] _).andThen(Apply[F].apF(ff)).andThen(Bind[F].join)(a)
import scalaz.std.list._
extract(List((x: Int) => List(x, x)))(3) // List(3, 3)