在scala中组合变量类型的函数序列

在scala中组合变量类型的函数序列,scala,types,higher-order-functions,function-composition,Scala,Types,Higher Order Functions,Function Composition,我要做的是对数据集应用一系列的转换,其中每个函数获取前一步的输出,并为下一步进行转换。例如 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)(_) p

我要做的是对数据集应用一系列的转换,其中每个函数获取前一步的输出,并为下一步进行转换。例如

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,它接受一个输入a Seq(f1,f2,…)并返回它们的链接,其中f1,f2,…,fn并不都具有相同的输入和相同的输出类型T。但是它们是可组合的,例如:

f1: Function1[A,B]
f2: Function1[B,C]
f3: Function1[C,D]
然后链接函数将返回一个函数 f:[A,D]

谢谢,
Z

这里有两个解决方案建议:

  • 一种解决方案,需要一种特殊的列表,可以跟踪函数链中的所有类型
  • 是一种对普通列表有效的重型解决方案

  • 跟踪所有类型的中间结果

    普通列表将无法跟踪所有中间结果的类型。以下是跟踪所有这些类型的函数列表:

    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]
    
    一个小测试:

    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
    

    只是
    所有东西的替代品

    这是一个不太精细但短得多的解决方案:

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

    你能澄清一下这个问题吗?到底什么地方不清楚?@ZoharEtzioni在表现上应该没有任何区别。在运行时,所有类型都会被擦除,剩下的函数组成完全相同。这两种解决方案之间的差异只有在编译时才可见,因为第一种解决方案在保证所有类型按预期匹配方面做得更好。你是对的,如果I/O不匹配,前一种方法将无法编译,而后一种方法将在运行时失败。我喜欢!谢谢
    println(andThenAll[Int, String](List(f1, f2, f3))(42))