我需要从monad中提取函数,这对于任何monad都是可能的:
def extractf[A, B, F[_]: Monad](ff: F[A ⇒ F[B]]): A ⇒ F[B] = a ⇒ {
Monad[F].bind(ff)(f ⇒ f(a))
}
我无法在scalaz和hoogle中找到这样的功能。
我尝试使用Kleisli上的测序(想法是做序列。加入)或不提升来实现相同的目标,但这变得过于复杂,所以我停止了。
我的问题是 - 我是否因为任何原因未能找到此功能或没有人使用它(如果是,那么如何实现相同的目标)?
谢谢!
答案 0 :(得分:0)
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的回归一样。然后我们使用Apply的apF(Applicative的弱化变体)来将参数替换为仿函数中的函数,从F [A]获得F [F [B]]并且F [A => 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)