我不知道这方面的技术术语,但正如标题中所述,我正在寻找类型类的函数或特性,它将输出一对容器的函数转换为包含容器的容器。一双。它的签名应该看起来像
def f[M[_], A, B, C](g: A => (M[B], M[C])): A => M[(B, C)]
要实现这一点,可能需要首先指定一个允许映射(M[A], M[B]) => M[(A, B)]
的类型类,然后使用此类型的功能组成g
。
作为一个具体的例子,假设我们有一个函数f: Int => Option[Int]
和一个函数g: Int => Option[Long]
。我们可以"配对"使用scalaz(val h = f &&& g
)中的箭头语法的函数,使得结果函数(h
)具有类型Int => (Option[Int], Option[Long])
。然后,我们可以使用for-comprehension或通过与Option
合成来对(a, b) => a tuple b
进行排序。这是如何概括的?
编辑:
发布此消息后不久,我发现scalaz7中的tuple
功能来自Apply
类型类,而不是来自Option
。显然,这是一个比Applicative
更弱的类,这解释了为什么它使用monadic for-understanding进行工作。因此,Apply应该在一般情况下完成工作。我现在的问题是:如何将原始A => (M[B], M[C])
直接转换为A => M[(B, C)]
,而不将Apply
的功能与原始功能的功能组合在一起?
答案 0 :(得分:0)
试试这个?我没有安装scalaz。
def f[M <: Monad[M[_]], A, B, C](g: A => (M[B], M[C])): A => M[(B, C)] = (a: A) => {
g(a) match {
// For general monads, converts (M[B],M[C]) to M[(B, C)]
case (b, c) => b.map((_, c)).flatMap(k => k._2.map((k._1, _)))
}
}
答案 1 :(得分:0)
应用我需要的东西,下面似乎工作。我希望有更简洁的语法糖,但它完成了工作:
def pairApply[M[_] : Apply, A, B, C](g: A => (M[B], M[C])): A => M[(B, C)] = {
g andThen (x => implicitly[Apply[M]].tuple2(x._1, x._2))
}
关注bazzargh's comment,使用scalaz的Zip可以更清楚一点:
def zipPair[M[_] : Zip, A, B, C](g: A => (M[B], M[C])): A => M[(B, C)] = {
g andThen (x => x._1 fzip x._2)
}
虽然构图仍不理想。
答案 2 :(得分:0)
还有bisequence
,它允许你将一个应用程序元组内外翻出来:
def zipPair[M[_]: Applicative, A, B, C](g: A => (M[B], M[C])): A => M[(B, C)] =
g.andThen(_.bisequence[M, B, C])
它比Zip
更通用,因为它适用于任何带有Bitraverse
实例的类型(例如Either
),而不仅仅是元组。