lazy sequence: ambiguous use of 'filter'

Hi,


I'm currently experimenting with sequences and encountered the following strange behaviour.


Suppose I have the following unlimited sequence of Fibonacci numbers:


let fibonacciNumbers = AnySequence { () -> AnyGenerator<Int> in
    var i = 0
    var j = 1
    return anyGenerator {
        (i, j) = (j, i + j)
        return i
    }
}


Apparently I cannot use

filter
or
map
directly on this sequence because both functions return arrays. Instead I need to create a lazy view of this sequence by using the
lazy
property.


OK, let's compute the first 10 even Fibonacci numbers:


let tenEvenFibs = fibonacciNumbers.lazy.filter({ $0 % 2 == 0 }).prefix(10)


However, for this line XCode reports the following error:


Playground execution failed: error: ambiguous use of 'filter'

let tenEvenFibs = fibonacciNumbers.lazy.filter({ $0 % 2 == 0 }).prefix(10)

^

Swift.SequenceType:10:17: note: found this candidate

public func filter(@noescape includeElement: (Self.Generator.Element) throws -> Bool) rethrows -> [Self.Generator.Element]

^

Swift.LazySequenceType:9:17: note: found this candidate

public func filter(predicate: (Self.Elements.Generator.Element) -> Bool) -> LazyFilterSequence<Self.Elements>

^


(the caret in the first error message points to the lazy property)


As I understand this error, the swift compiler doesn't know which filter method to apply because there are two candidates with equal parameter types.


However, if I split this line into two assignments, then the compiler has no problems:


let evenFibs = fibonacciNumbers.lazy.filter({ $0 % 2 == 0 })
let tenEvenFibs = evenFibs.prefix(10)


What's wrong with the one-liner?

(Using XCode 7.2 beta)

Replies

I don't know the whole answer, but the half-answer is that assigning the result of the filter operation to a variable fixes its type.


When you chain from one method to another without fixing the intermediate type (e.g., filter().prefix()), the type inference engine has to consider the variants available at each step in order to come up with a consistent interpretation for the whole chain. For example,


LazySequence<AnySequence<Int>> -> filter -> [Int] -> prefix -> ArraySlice<Int>


is one possible path through the chain, as is


LazySequence<AnySequence<Int>> -> filter -> AnySequence<Int> -> prefix -> AnySequence<Int>


Evidently, the normal priority rules for function overloading don't apply in exactly the same way in this context. My guess is that type inference for call chains has been made more restrictive because of the potential for multiplicative complexity.


You can disambiguate by telling the compiler which result you're expecting to obtain:


let tenEvenFibs: AnySequence<Int> = fibonacciNumbers.lazy.filter({ $0 % 2 == 0 }).prefix(10) // Works