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。您在这里想要实现什么?你能展示一个实际的用例吗?