组成懒惰序列转换的快速问题



我正在继续锻炼功能迅速,并且非常享受挑战。我正在处理将元素变成懒惰序列的变换。

要提前陈述错误,我得到了:无法转换类型的价值"变换"(又名'(int) ->懒惰>')预期参数类型'() ->懒惰效果< []>'

我的问题在于编写它们,但我需要给出一些上下文以显示问题。

这是转换:

typealias Transform<T, U> = (T) -> LazySequence<[U]>

我可以定义远期应用程序:

precedencegroup LazyForwardApplication {
  associativity: left
}
infix operator |~>: LazyForwardApplication
func |~> <T: LazySequenceProtocol, U>(
  input: T,
  transform: @escaping Transform<T.Elements.Element,U>
  ) -> LazySequence<FlattenSequence<LazyMapSequence<T.Elements, LazySequence<[U]>>>> {
  return input.flatMap(transform)
}

返回类型有点嘴巴,但效果很好:

let start = [10,20,30].lazy
let add4_5_6: Transform<Int, Int> = {
  let result = [ $0 + 4, $0 + 5, $0 + 6]
  print("> add4_5_6(($0)) -> (result)")
  return result.lazy
}

//请注意,我部分进行了调试,以便我确定它懒洋洋地发生。

let result1 = start |~> add4_5_6
result1.forEach{ print($0) }
// 14, 15, 16, 24, 25, 26, 34, 35, 36

和另一个类似的示例:

let add7000_8000: Transform<Int, Int> = {
  let result = [ $0 + 7000, $0 + 8000]
  print("> add7000_8000(($0)) -> (result)")
  return result.lazy
}
let result2 = start |~> add7000_8000
result2.forEach{ print($0) }
// 7010, 8010, 7020, 8020, 7030, 8030

我可以将它们链接在一起:

// Double application
let result3 = start |~> add4_5_6 |~> add7000_8000
result3.forEach{ print($0) }
// 7014, 8014, 7015, 8015, 7016, 8016,
// 7024, 8024, 7025, 8025, 7026, 8026,
// 7034, 8034, 7035, 8035, 7036, 8036

,但我也想能够撰写它们:

// Forward Composition
precedencegroup LazyForwardComposition {
  associativity: right
}
infix operator >~>: LazyForwardComposition
func >~> <T, U: Sequence, V: Sequence>(
  left:  @escaping Transform<T,U>,
  right: @escaping Transform<U,V>
  ) -> (T) -> LazySequence<FlattenSequence<LazyMapSequence<[U], LazySequence<[V]>>>> {
  return { input in
    let b: LazySequence<[U]> = left(input)
    let c = b.flatMap(right)
    return c
  }
}

这是我遇到错误的地方:

let composed = add4_5_6 >~> add7000_8000
// ERROR IN ABOVE LINE: Cannot convert value of type
'Transform<Int, Int>' (aka '(Int) -> LazySequence<Array<Int>>')
to expected argument type
'(_) -> LazySequence<[_]>'
let result4 = start |~> composed
result4.forEach{ print($0) }

结果将与结果3

相同

我已经在这圈工作了几次,但一直被卡住。关于如何解决的任何想法。

(我以前的问题是类似的领域,但另一个问题:Swift:懒洋洋地封装地图,过滤器,Flatmap的链条)

对于游乐场:

typealias Transform<T, U> = (T) -> LazySequence<[U]>
// And I can define Forward Application:
precedencegroup LazyForwardApplication {
  associativity: left
}
infix operator |~>: LazyForwardApplication
func |~> <T: LazySequenceProtocol, U>(
  input: T,
  transform: @escaping Transform<T.Elements.Element,U>
  ) -> LazySequence<FlattenSequence<LazyMapSequence<T.Elements, LazySequence<[U]>>>> {
  return input.flatMap(transform)
}
// The return type is a bit of a mouthful but it works fine:
let start = [10,20,30].lazy
let add4_5_6: Transform<Int, Int> = {
  let result = [ $0 + 4, $0 + 5, $0 + 6]
  print("> add4_5_6(($0)) -> (result)")
  return result.lazy
}
// Note that I put the debug in partly so I can be sure that it's happening lazily.
let result1 = start |~> add4_5_6
result1.forEach{ print($0) }
// 14, 15, 16, 24, 25, 26, 34, 35, 36
// And another similar example:
let add7000_8000: Transform<Int, Int> = {
  let result = [ $0 + 7000, $0 + 8000]
  print("> add7000_8000(($0)) -> (result)")
  return result.lazy
}
let result2 = start |~> add7000_8000
result2.forEach{ print($0) }
// 7010, 8010, 7020, 8020, 7030, 8030
// And I can chain these together inline: 
// Double application
let result3 = start |~> add4_5_6 |~> add7000_8000
result3.forEach{ print($0) }
// 7014, 8014, 7015, 8015, 7016, 8016,
// 7024, 8024, 7025, 8025, 7026, 8026,
// 7034, 8034, 7035, 8035, 7036, 8036
// But I'd like to be able to compose them too:
// Forward Composition
precedencegroup LazyForwardComposition {
  associativity: right
}
infix operator >~>: LazyForwardComposition
func >~> <T, U: Sequence, V: Sequence>(
  left:  @escaping Transform<T,U>,
  right: @escaping Transform<U,V>
  ) -> (T) -> LazySequence<FlattenSequence<LazyMapSequence<[U], LazySequence<[V]>>>> {
  return { input in
    let b: LazySequence<[U]> = left(input)
    let c = b.flatMap(right)
    return c
  }
}
// And here's where I get an error:
let composed = add4_5_6 >~> add7000_8000
// ERROR IN ABOVE LINE: Cannot convert value of type 'Transform<Int, Int>' (aka '(Int) -> LazySequence<Array<Int>>') to expected argument type '(_) -> LazySequence<[_]>'
let result4 = start |~> composed
result4.forEach{ print($0) }
// The result would come out the same as result3

我有部分答案,但也许可以帮助您到达某个地方。

首先,Transform<T, U>定义为(T) -> LazySequence<[U]>,因此UV通用类型不能被专业化为Sequence

func >~> <T, U, V>(
    left:  @escaping Transform<T,U>,
    right: @escaping Transform<U,V>
    ) -> (T) -> LazySequence<FlattenSequence<LazyMapSequence<[U], LazySequence<[V]>>>> {
    return { input in
        let b = left(input)
        let c = b.flatMap(right)
        return c
    }
}

第二,您的|~>操作员接受Transform作为右手参数,因此您无法将其与>~>参数的返回类型一起使用。我能够通过以下行获得结果:

let result4 = start.flatMap(composed)

您可能会超载|~>操作员以接受正确的类型,但看起来不好。也许会有足够的打字:)

相关内容

  • 没有找到相关文章

最新更新