scala - 如何在函数中平面嵌套元组参数?
问题描述
我有一个g
需要参数的函数(Int, (Int, Int)) => Int
和一个平面函数f0
(Int, Int, Int) => Int
我想构造一个可以将to的ft
参数变平的函数。这是示例:g
f0
val f0: ((Int, Int, Int)) => Int = (x: (Int, Int, Int)) => {
x._1 + x._2 + x._3
}
def g(f: ((Int, (Int, Int))) => Int): Int = f(1,(2,3))
def ft(f: ((Int, Int, Int)) => Int): ((Int, (Int, Int))) => Int = (p: (Int, (Int, Int))) => {
f(p._1, p._2._1, p._2._2)
}
// invoke it
g(ft(f0))
但是我有几个嵌套元组的函数,我不想手动转换每个函数。例如,((Int, Int), (Int, Int)) => Int
要(Int, Int, Int, Int) => Int
这里说可以用shapeless
那么新功能就好了
import shapeless._
import ops.tuple.FlatMapper
trait LowPriorityFlatten extends Poly1 {
implicit def default[T] = at[T](Tuple1(_))
}
object flatten extends LowPriorityFlatten {
implicit def caseTuple[P <: Product](implicit lfm: Lazy[FlatMapper[P, flatten.type]]) =
at[P](lfm.value(_))
}
def ft(f: ((Int, Int, Int)) => Int): ((Int, (Int, Int))) => Int = (p: (Int, (Int, Int))) => {
val a: (Int, Int, Int) = flatten(p).asInstanceOf[(Int, Int, Int)]
f(a)
}
上面的代码有两个问题:
- 如何定义
ft[A, B, C](f: A => C): B
扁平A
化类型的函数B
? flatten(p)
将产品类型FlatMapper.this.Out
和错过类型,所以我asInstanceOf
在这里使用转换类型。
那么,如何编写一个函数来展平参数中的任何类型的嵌套元组?
解决方案
以下代码适用于 Scala 3:
scala> type Flat[T <: Tuple] <: Tuple = T match
| case EmptyTuple => EmptyTuple
| case h *: t => h match
| case Tuple => Tuple.Concat[Flat[h], Flat[t]]
| case _ => h *: Flat[t]
|
scala> def flat[T <: Tuple](v: T): Flat[T] = (v match
| case e: EmptyTuple => e
| case h *: ts => h match
| case t: Tuple => flat(t) ++ flat(ts)
| case _ => h *: flat(ts)).asInstanceOf[Flat[T]]
def flat[T <: Tuple](v: T): Flat[T]
scala> def ft[A <: Tuple, C](f: Flat[A] => C): A => C = a => f(flat(a))
def ft[A <: Tuple, C](f: Flat[A] => C): A => C
scala> val f0: ((Int, Int, Int)) => Int = x => x._1 + x._2 + x._3
scala> def g0(f: ((Int, (Int, Int))) => Int): Int = f(1,(2,3))
scala> g0(ft(f0))
val res0: Int = 6
编辑:添加 scala2 的版本:
import shapeless._
import ops.tuple.FlatMapper
import syntax.std.tuple._
trait LowPriorityFlat extends Poly1 {
implicit def default[T] = at[T](Tuple1(_))
}
object Flat extends LowPriorityFlat {
implicit def caseTuple[P <: Product](implicit fm: FlatMapper[P, Flat.type]) =
at[P](_.flatMap(Flat))
}
type F[A, B] = FlatMapper.Aux[A, Flat.type, B]
def flatTup[T <: Product](t: T)(implicit lfm: FlatMapper[T, Flat.type]): lfm.Out =
FlatMapper[T, Flat.type].apply(t)
def flatFun[A <: Product, B <: Product, C](f: B => C)
(implicit lfm: F[A, B]): A => C =
a => f(flatTup(a))
val f0: ((Int, Double, Int, Double)) => Double = { case(i1, d1, i2, d2) => (i1 + i2) / (d1 + d2) }
def g0(f: (((Int, Double), (Int, Double))) => Double): Double = f((1, 2.0), (3, 4.0))
val r0 = g0(flatFun(f0))
推荐阅读
- javascript - Onclick 事件 - 多次点击
- python - 如何在Python的父目录中的文件夹中进行文件的相对导入
- r - 为什么使用 ggscatter 会导致资金(从左到右)错误?
- python - Python:Pickle 如何与 defaultdict 一起工作
- java - 无法让 rJava 在 MacOS 10.14 中正常工作
- python - conda create -n anaconda 不会安装完整的 anaconda 软件包
- sorting - 堆索引示例说明
- assembly - 如何设置进位标志添加两个数字(32位)
- pyspark - Pyspark如何删除标点符号并在Rdd中制作小写字母?
- swift - 如何在 Xcode 9.4 中使 Optionals 可散列