函数式编程依赖:如何在没有直接连接在一起的函数之间共享依赖

Functional Programming Dependencies: How to share dependencies between functions that aren't connected together direct

这些不同的函数像这样组合在一起[=13​​=]

f1 -> f2 -> f3 -> f4 -> f5

我需要在 f3 周围添加两个新函数 fx 和 fy,如下所示:

f1 -> f2 -> fx -> f3 -> fy -> f4 -> f5

所以我需要预处理 f3 的参数,然后 post 处理 f3

的输出

此处函数 fx 进行了更改,fy 将更改还原,但 fy 需要 fx 的其他详细信息才能还原,例如要知道要还原到哪些值

问题是函数 fx 需要产生两个输出

first: output that is needed by f3
second: output that is needed by fy

问题: 如何在没有直接连接在一起的函数之间共享依赖关系, 有空间 way/technique 来解决这个问题吗?

仅供参考,我正在使用 Java8

我通过创建 fk 函数来解决这个问题,该函数通过在它之前调用 fx 并在它之后调用 fy 来包装 f3,这样我就能够共享所需的状态位,这类似于 Aadit 建议的箭头。

我将对所有函数 return 值使用某种类型 A;您将需要自己整理出真实的类型。

这是您描述的意图:

  • 函数fx将产生两个参数,我们称它们为ab
  • 函数 f3 将处理值 a 并产生 a'.
  • 最后,fy 将消耗 a'b 并产生 c

让我们看看如何实现(我将为类型签名编写伪代码):

  1. fy 定义为接受两个参数和 return 一个参数的函数:

    (A, A) => A
    
  2. 定义 fyp("fy preprocessed" 的缩写)作为一个函数,它采用一些预处理函数 p 并执行您的 fy 的逻辑,但第一个参数使用 p 进行了预处理。我们将把它写成 P => FY 的形式,其中 P 是预处理函数的类型签名, FYfy 的类型签名:

    P => FY, which expands to  
    (A => A) => (A, A) => A
    

    所以这个函数的实现应该以A => A类型的预处理函数p作为输入,执行fy的逻辑(这是右边,(A, A) => A...注意它是如何对应fy)的签名的,但是在执行逻辑之前,它会将fy的第一个参数映射到p。这里有一些 Scala 实现供参考(我不太擅长 Java):

    val fyp: (A => A) => ((A, A)) => A =              
      f => fyuParams => performFyLogic((f(fyuParams._1), fyuParams._2))  
    

    其中 performFyLogic 是您的 fy 函数的实际处理逻辑。

  3. 定义最终构图为:

    f1 -> f2 -> fx -> fyp(f3)
    

这里有完整的 Scala 实现供参考(同样,对 Java 8 不是很了解):

val f1: Int => Int = _ + 1
val f2: Int => Int = _ + 2
val f3: Int => Int = _ + 3

val fx: Int => (Int, Int) = i => (i + 4, i + 5)

// let's assume that the original fy simply sums up its two parameters
val fyp: (Int => Int) => ((Int, Int)) => Int =
  f => fyArgs => f(fyArgs._1) + fyArgs._2

val composed1 = f1 andThen f2 andThen f3
println(composed1(42)) // 48

val composed2 = f1 andThen f2 andThen fx andThen fyp(f3)
println(composed2(42)) // 102

// because:
// f1 -> f2 -> fx = (42 + 1 + 2 + 4, 41 + 1 + 2 + 5) = (49, 50)
// fyp(f3)((49, 50)) = (49 + 3) + 50 = 102