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

时间:2016-05-06 14:05:37

标签: 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) } }

但是有可能以更通用的方式做吗?如果我有两个以上具有不同参数的函数,如何将它们组合起来以便可以使用f: (T1,T2,...,TN) => Unit回调进行调用?

2 个答案:

答案 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) => UnitOneCallback转换为一个回调,将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个参数的限制,因为一切都是嵌套的元组。