假设我有以下两个功能。
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
回调进行调用?
答案 0 :(得分:2)
这可能会有点矫枉过正,但你可以使用无形的方式做这样的事情。
我们可以将一些副作用回调函数表示为from unitapp in context.unit_apportionment
join unitappdate in context.unit_apportionment_date on unitapp.uri equals unitappdate.unit_apportionment_uri
join pes in context.property_expense_schedule on unitapp.property_expense_schedule_uri equals pes.uri
join unitmestot in context.unit_measurement_total on unitapp.property_ref equals unitmestot.property_ref
into unitapp_unitmesstot from unitmestot in unitapp_unitmesstot.DefaultIfEmpty() // Left Outer Join
join units in context.units on unitmestot.uri equals units.prime_measurement_uri
select new Apportionment()
{
// ...
}
:
from unitapp in context.unit_apportionment
join unitappdate in context.unit_apportionment_date on unitapp.uri equals unitappdate.unit_apportionment_uri
join pes in context.property_expense_schedule on unitapp.property_expense_schedule_uri equals pes.uri
join right in (
from unitmestot in context.unit_measurement_total
join units in context.units on unitmestot.uri equals units.prime_measurement_uri
select new { unitmestot, units }
) on unitapp.property_ref equals right.unitmestot.property_ref
into outerJoin from right in outerJoin.DefaultIfEmpty() // Left Outer Join
let unitmestot = right.unitmestot
let units = right.units
select new Apportionment()
{
// ...
}
现在我们要将最后一个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
为参数的函数。
首先,我们将介绍一个类型类HList
,它可以将(Int, String) => Unit
像OneCallback
转换为一个回调,将HList
作为参数(包含所有不同的参数)多个功能)。对于callbacks
,我们会获得HList
。
callbacks
我们将创建一个可以将此Callback[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)
}
}
}
}
的函数:
Callback[Int :: String :: HNil]
现在我们可以将多个回调函数组合为:
((Int, String) => Unit) => Unit
答案 1 :(得分:2)
我知道这不是特别优雅或易于编写,但我认为它很容易实现和理解
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个参数的限制,因为一切都是嵌套的元组。