Scala 将多个函数与回调参数组合在一起

Scala 将多个函数与回调参数组合在一起,scala,functional-programming,Scala,Functional Programming,假设我有以下两个函数 def f1(f: T1 => Unit): Unit = ??? def f2(f: T2 => Unit): Unit = ??? 我想把f1和f2组合成一些函数f3 f3(f: (T1,T2) => Unit): Unit 我可以很容易地实现这种简单的情况 def f3(f: (T1,T2) => Unit) = f1 { t1 => f2 { t2 => f(t1,t2) } } 但有没有可能用更一般的方式来做呢?如果我有两

假设我有以下两个函数

def f1(f: T1 => Unit): Unit = ???
def f2(f: T2 => Unit): Unit = ???
我想把f1和f2组合成一些函数f3

f3(f: (T1,T2) => Unit): Unit
我可以很容易地实现这种简单的情况

def f3(f: (T1,T2) => Unit) = f1 { t1 => f2 { t2 => f(t1,t2) } }

但有没有可能用更一般的方式来做呢?如果我有两个以上具有不同参数的函数,那么如何将它们组合起来,以便能够使用
f:(T1,T2,…,TN)=>Unit
callback进行调用?

这可能会有些过分,但可以使用shapeless进行类似的操作

我们可以将几个副作用回调函数表示为
HList

import shapeless._

type Callback[A] = (A => Unit) => Unit

def f1(f: Int => Unit): Unit = f{ println("f1"); 5 }
val f2: Callback[String] = f => f{ println("f2"); "foo" }

val callbacks = f1 _ :: f2 :: HNil
// Callback[Int] :: Callback[String] :: HNil
import shapeless.ops.function.FnToProduct

def oneCallback[CS <: HList, A <: HList, C](callbacks: CS)(implicit 
  ocb: OneCallback[CS, A],
  ftp: FnToProduct.Aux[C, A => Unit]
): C => Unit = c => ocb(callbacks).apply(ftp(c))
现在我们想把最后一个
HList
转换成一个函数,该函数以
(Int,String)=>单元作为参数

首先,我们将引入一个类型类
OneCallback
,它可以将
HList
callbacks
转换为一个回调,并将
HList
作为参数(由多个函数的所有不同参数组成)。对于
回调
我们将得到一个
回调[Int::String::HNil]

trait OneCallback[F, Args] {
  def apply(funs: F): Callback[Args]
}

object OneCallback {
  implicit val hnilOneCallback: OneCallback[HNil, HNil] = 
    new OneCallback[HNil, HNil] {
      def apply(funs: HNil): Callback[HNil] = callback => callback(HNil)
    }

  implicit def hconsCallback[A, FT <: HList, AT <: HList](implicit 
    oneCallbackTail: OneCallback[FT, AT]
  ) = new OneCallback[Callback[A] :: FT, A :: AT] {
    def apply(funs: Callback[A] :: FT): Callback[A :: AT] = 
      (f: (A :: AT) => Unit) =>
        funs.head { argH =>
          oneCallbackTail(funs.tail) { argsT =>
            f(argH :: argsT)
          }
        }
  }
}
现在,我们可以将多个回调函数组合为:

val cb = oneCallback(f1 _ :: f2 :: HNil)
cb { (i, s) => println(s * i) }
// f1
// f2
// foofoofoofoofoo

我知道这不是特别优雅或容易写,但我认为它很容易实现和理解

val f1: String => Unit = s => println(s)
val f2: Int => Unit = i => println(i)
val f3: Double => Unit = d => println(d)


implicit class Chain[A](f: A => Unit) {
  def o [B](g: B => Unit): Tuple2[A, B] => Unit =  {
    case (x, y) => f(x); g(y)
  }
}

(f1 o f2 o f3) ("a" -> 1 -> 2.0)

编辑:这实际上比我预期的要好。没有22个参数的限制,因为所有参数都是嵌套的tuple2。

您在这里想要实现什么?你能展示一个实际的用例吗?