Global function sequence(state:next:) and type inference

前端 未结 2 1784
攒了一身酷
攒了一身酷 2020-12-11 23:51

Background & details

Swift evolution proposal SE-0094 was implemented in Swift 3.0, introducing the global sequence functions:

  • sequenc
相关标签:
2条回答
  • 2020-12-12 00:07

    But even admitting that this is a bug, you can still make the code look a lot nicer instead of worrying about it (typed in the browser without testing, but something like this should work):

    typealias MyTriple = (Bool, ClosedRangeIterator<Int>, ClosedRangeIterator<Int>)
    let someTriple : MyTriple = (false, seq1.makeIterator(), seq2.makeIterator())
    let combined = sequence(state: someTriple) { 
        (iters: inout MyTriple) -> Int? in
        iters.0 = !iters.0
        return iters.0 ? iters.1.next() : iters.2.next()
    }
    
    0 讨论(0)
  • 2020-12-12 00:24

    This looks like a combination of two issues.

    The first is that Swift currently doesn't infer the type of a multi-line closure without any external context. This is however intended behaviour, as confirmed by Apple developer Jordan Rose in the comments of SR-1570:

    This is correct behavior: Swift does not infer parameter or return types from the bodies of multi-statement closures. But the diagnostic could be a lot better.

    Therefore in theory, you would just need to explicitly define the return type of the closure you pass to sequence()'s next: parameter, as the parameter type can be inferred from external context (namely the type you pass into the state: parameter):

    let seq1 = 1...3
    let seq2 = 4...6
    
    let combined = sequence(state: (false, seq1.makeIterator(), seq2.makeIterator()),
                            next: { iters -> Int? in
        iters.0 = !iters.0
        return iters.0 ? iters.1.next() : iters.2.next()
    })
    

    (Edit: This now compiles in Swift 3.1)


    However, this still doesn't compile – which is due to the second issue, where the compiler cannot infer the type for an inout closure parameter in Swift 3 (which wasn't the case in Swift 2). This is a suspected bug, which has already been filed (see both SR-1976 & SR-1811).

    Therefore, as you note in the question, this means (quite unsatisfactorily) that you have to explicitly annotate the full closure signature that you pass to next::

    let combined = sequence(state: (false, seq1.makeIterator(), seq2.makeIterator()),
                            next: { (iters: inout (Bool, ClosedRangeIterator<Int>, ClosedRangeIterator<Int>)) -> Int? in
        iters.0 = !iters.0
        return iters.0 ? iters.1.next() : iters.2.next()
    })
    
    0 讨论(0)
提交回复
热议问题