Scala 将(A=>;(M[B],M[C])转换为(A=>;M[(B,C)])

Scala 将(A=>;(M[B],M[C])转换为(A=>;M[(B,C)]),scala,functional-programming,implicit,scalaz,Scala,Functional Programming,Implicit,Scalaz,我不知道这方面的技术术语,但正如标题中所述,我正在寻找一个函数或typeclass的特性,它将输出一对容器的函数转换为包含一对容器的容器。它的签名应该是 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:In

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

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(
valh=f&&g
)中的箭头语法对函数进行“配对”,以使生成的函数(
h
)具有类型
Int=>(选项[Int],选项[Long])
。然后,我们可以通过使用a进行理解或使用
(a,b)=>a元组b来对
选项
排序。这是如何概括的

编辑:


发布这篇文章后不久,我发现scalaz7中的
tuple
功能来自
Apply
typeclass,而不是直接来自
选项。显然,这是一个比
Applicative
弱的类,这就解释了为什么它使用一元来理解。因此,在一般情况下,应用程序应该完成工作。我现在的问题是:如何将原始的
A=>(M[B],M[C])
直接转换为
A=>M[(B,C)]
,而不必编写
的功能与原始函数的功能结合起来?

试试这个?我没有安装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, _)))
   }
}
def[M(M[B],M[C]):A=>M[(B,C)]=(A:A)=>{
g(a)比赛{
//对于一般单子,将(M[B],M[C])转换为M[(B,C)]
案例(b,c)=>b.map((uu,c)).flatMap(k=>k.2.map((k.1,u)))
}
}

Apply具备了我所需要的功能,下面的内容似乎很有效。我原本希望得到更简洁的语法糖,但它完成了任务:

  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))
  }
下面,使用scalaz的拉链可以让这一点更加清晰:

  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)
  }

不过,组合仍然不理想。

还有
双序列
,可以让您将应用程序的元组翻过来:

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
实例的任何类型(例如
),而不仅仅是元组。

对,我知道如何在选项的特定情况下做到这一点。我试图以更简洁的方式概括该方法。请参阅我的编辑。在研究了一点之后,可能需要通过
Apply
type类来完成。谢谢。这是可行的,但事实证明,这可以通过
Apply
单独完成(也就是说,它可以进一步推广)。见下面我的答案。你知道有没有更简短、更清晰的方法来实现这一点吗?也许是个愚蠢的问题,因为我不会说scalaz,但“一个函数将一对容器输出到一个包含一对容器的容器中”不是zip?我在scalaz文档中找到了它,看起来它做了一些类似于你想要的事情:是的,看起来就是这样!