将(A =>(M [B],M [C]))变换为(A => M [(B,C)])

时间:2014-02-21 23:40:55

标签: scala functional-programming implicit scalaz

我不知道这方面的技术术语,但正如标题中所述,我正在寻找类型类的函数或特性,它将输出一对容器的函数转换为包含容器的容器。一双。它的签名应该看起来像

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的功能与原始功能的功能组合在一起?

3 个答案:

答案 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),而不仅仅是元组。

相关问题