在scala中组成一系列变量类型的函数
Composing a sequence of functions of variable types in scala
我想做的是将一系列转换应用于数据集,其中每个函数都采用上一步的输出并将其转换为下一步。例如
val f1: Function1[Int, Double] = _ / 2d
val f2: Function1[Double, BigDecimal] = x=>BigDecimal(x - 2.1)
val f3: Function1[BigDecimal, String] = _.toString
val chained = (f1 andThen f2 andThen f3)(_)
println(chained(10))
我想要的是一个函数 f,它接受一个输入 Seq(f1, f2, ...) 和 returns 它们的链接,其中 f1, f2, ...fn 不都具有相同的输入和输出类型 T。但是它们是可组合的,例如:
f1: Function1[A,B]
f2: Function1[B,C]
f3: Function1[C,D]
那么链接函数将return一个函数
f: [A,D].
谢谢,
Z
这里有两个解决方案:
- 需要一种特殊列表的解决方案,可以跟踪函数链中的所有类型。
- 一个
asInstanceOf
-heavy 解决方案,适用于普通列表。
跟踪所有类型的中间结果
普通列表会忘记所有中间结果的类型。以下是跟踪所有这些类型的函数列表:
sealed trait Func1List[-In, +Res] {
def ::[I, O <: In](h: I => O): Func1List[I, Res] = ConsFunc1(h, this)
}
object Func1List {
def last[In, Res](f: In => Res): Func1List[In, Res] = LastFunc1(f)
def nil[A]: Func1List[A, A] = LastFunc1(identity)
}
case class LastFunc1[-In, +Res](f: In => Res)
extends Func1List[In, Res]
case class ConsFunc1[-In, Out, +Res](head: In => Out, tail: Func1List[Out, Res])
extends Func1List[In, Res]
现在,对于 Func1List
,我们可以定义一个连接所有元素的函数:
def andThenAll[A, Z](fs: Func1List[A, Z]): A => Z = fs match {
case LastFunc1(f) => f
case c: ConsFunc1[A, t, Z] => c.head andThen andThenAll[t, Z](c.tail)
}
小测试:
val f1: Function1[Int, Double] = _ / 2d
val f2: Function1[Double, BigDecimal] = x => BigDecimal(x - 2.1)
val f3: Function1[BigDecimal, String] = _.toString
val fs = f1 :: f2 :: Func1List.last(f3)
val f = andThenAll(fs)
println(f(42)) // prints 18.9
只是asInstanceOf
所有的东西
一个不太精致但更短的解决方案:
def andThenAll[X, Y](fs: List[_ => _]): X => Y = fs match {
case Nil => (identity[X] _).asInstanceOf[X => Y]
case List(f) => f.asInstanceOf[X => Y]
case hd :: tl => hd match {
case f: Function1[X @unchecked, o] => f andThen andThenAll[o, Y](tl)
}
}
这也会导致 18.9
:
println(andThenAll[Int, String](List(f1, f2, f3))(42))
我想做的是将一系列转换应用于数据集,其中每个函数都采用上一步的输出并将其转换为下一步。例如
val f1: Function1[Int, Double] = _ / 2d
val f2: Function1[Double, BigDecimal] = x=>BigDecimal(x - 2.1)
val f3: Function1[BigDecimal, String] = _.toString
val chained = (f1 andThen f2 andThen f3)(_)
println(chained(10))
我想要的是一个函数 f,它接受一个输入 Seq(f1, f2, ...) 和 returns 它们的链接,其中 f1, f2, ...fn 不都具有相同的输入和输出类型 T。但是它们是可组合的,例如:
f1: Function1[A,B]
f2: Function1[B,C]
f3: Function1[C,D]
那么链接函数将return一个函数 f: [A,D].
谢谢, Z
这里有两个解决方案:
- 需要一种特殊列表的解决方案,可以跟踪函数链中的所有类型。
- 一个
asInstanceOf
-heavy 解决方案,适用于普通列表。
跟踪所有类型的中间结果
普通列表会忘记所有中间结果的类型。以下是跟踪所有这些类型的函数列表:
sealed trait Func1List[-In, +Res] {
def ::[I, O <: In](h: I => O): Func1List[I, Res] = ConsFunc1(h, this)
}
object Func1List {
def last[In, Res](f: In => Res): Func1List[In, Res] = LastFunc1(f)
def nil[A]: Func1List[A, A] = LastFunc1(identity)
}
case class LastFunc1[-In, +Res](f: In => Res)
extends Func1List[In, Res]
case class ConsFunc1[-In, Out, +Res](head: In => Out, tail: Func1List[Out, Res])
extends Func1List[In, Res]
现在,对于 Func1List
,我们可以定义一个连接所有元素的函数:
def andThenAll[A, Z](fs: Func1List[A, Z]): A => Z = fs match {
case LastFunc1(f) => f
case c: ConsFunc1[A, t, Z] => c.head andThen andThenAll[t, Z](c.tail)
}
小测试:
val f1: Function1[Int, Double] = _ / 2d
val f2: Function1[Double, BigDecimal] = x => BigDecimal(x - 2.1)
val f3: Function1[BigDecimal, String] = _.toString
val fs = f1 :: f2 :: Func1List.last(f3)
val f = andThenAll(fs)
println(f(42)) // prints 18.9
只是asInstanceOf
所有的东西
一个不太精致但更短的解决方案:
def andThenAll[X, Y](fs: List[_ => _]): X => Y = fs match {
case Nil => (identity[X] _).asInstanceOf[X => Y]
case List(f) => f.asInstanceOf[X => Y]
case hd :: tl => hd match {
case f: Function1[X @unchecked, o] => f andThen andThenAll[o, Y](tl)
}
}
这也会导致 18.9
:
println(andThenAll[Int, String](List(f1, f2, f3))(42))