如何在 Swift 中正确输入链式函数生成器函数?

问题描述 投票:0回答:1

特别是在 Swift 中(但老实说,我希望在任何类型语言中都有一个好的解决方案)我想正确键入一个 函数组合器函数

我确实对类型语言和泛型有相当多的经验,但对 Swift 还很陌生。由于我一直在 Swift 中偶然发现这个问题,那就是 atm。我的主要关注点,但我认为我不确定如何在任何类型函数中执行此操作,而不简单地将所有内容声明为

Any

(教科书上的)问题是这样的:

  1. 编写一个函数,该函数采用具有特定签名的函数数组并将它们组合起来,以便一个函数的输出作为下一个函数的输入。
  2. 使结果函数的类型为
    (I) -> O
    ,其中
    I
    是数组中第一个函数的输入类型,
    O
    是最后一个函数的输出类型。
  3. 让中间的每个函数(以某种方式)为
    (PreviousOut) -> MyOut
    类型,其中(当然)
    PreviousOut
    是之前函数的输出类型。

这是我到目前为止得到的:

func combine<I, O>(_ first: (I) -> Any, _ rest: ((Any) -> Any)...) -> (I) -> O {
  return { input in 
    let firstResult = first(input)
    return rest.reduce(firstResult) {$1($0)} as! O
  }
}

...适用于

I
类型,但是当然 “无法推断通用参数
O
即使如此,我们在组合函数调用之间仍然没有任何类型的保存。

--更新-- 这是一个固定示例,其中包含 3 个确实有效的处理器功能。虽然这显然不是我想要实现的目标,但它可能更好地说明了需要什么:

func combine<I, O, A, B>(
    _ first:@escaping (I) -> A,
    _ second:@escaping (A) -> B,
    _ third:@escaping (B) -> O
) -> (I) -> O {
  return {input in third(second(first(input)))}
}

有什么想法吗?

swift generics types functional-programming
1个回答
0
投票

不幸的是,即使考虑到新引入的类型参数包,你还是有点运气不好。

ATM,唯一的解决方案是编写

combine
函数的重载版本,这需要设置要支持的函数数量上限。

// zero functions
func combine() {
}

// one function
func combine<I, O>(_ f: @escaping (I) -> O) -> (I) -> O {
    f
}

// two functions
func combine<I, O, T>(
    _ f1: @escaping (I) -> T,
    _ f2: @escaping (T) -> O
) -> (I) -> O {
    { f2(f1($0)) }
}

// three functions
func combine<I, O, T1, T2>(
    _ f1: @escaping (I) -> T1,
    _ f2: @escaping (T1) -> T2,
    _ f3: @escaping (T2) -> O
) -> (I) -> O {
    { f3(f2(f1($0))) }
}

// four functions
func combine<I, O, T1, T2, T3>(
    _ f1: @escaping (I) -> T1,
    _ f2: @escaping (T1) -> T2,
    _ f3: @escaping (T2) -> T3,
    _ f4: @escaping (T3) -> O
) -> (I) -> O {
    { f4(f3(f2(f1($0)))) }
}

// and so on...

基本上,您必须在代码中手动编写所需数量的重载。

© www.soinside.com 2019 - 2024. All rights reserved.