Using Xcode 8 beta, swift 3 the second extension can not compiled. I don't understand if this is a swift bug or a known limitation.
extension Array {
func scanl<T>(initial: T, combine:(Iterator.Element, T) -> T) -> [T] {
guard let first = self.first else { return [] }
return [initial] + Array(self.dropFirst()).scanl(initial: combine(first, initial), combine: combine)
}
}
extension Array {
func scanl<T>(combine: (Iterator.Element, T) -> T) -> [T] {
guard let first = self.first else { return [] }
return Array(self.dropFirst()).scanl(initial:first, combine:combine)// Cannot convert value of type '(Element, T) -> T' To expected argument type '(_, _) -> _'
}
}
(Element, T) -> T is indeed the type of the function. So i cannot understand why the compiler expect (,) -> __ and what is this type mean beside "i don't care about the type"
This is not a bug or a limitation, it's simply impossible for the compiler to ascertain, at compile-time, that first
is of type T
in your second extension (as T
needn't necessarily be the same as Iterator.Element
). In both your closures, the compiler knows that first
is of type Iterator.Element
, but the compiler cannot know whether this is also type T
.
In your first extension, you only use first
as the first argument to the combine
closure, which expects just the type Iterator.Element
, so all is good.
In your second extension, however, you attempt to pass first
as an argument to a parameter (initial
) which expects type T
, and the compiler cannot know whether first
really is of type T
(the same type T
as used by the combine
closure used to call the two-argument scanl
), namely that Iterator.Element
of self
is of type T
. This can easily be redeemed by an attempted type conversion (as?
) of first
to T
in the optional binding clause of this second extension.
extension Array {
func scanl<T>(combine: (Iterator.Element, T) -> T) -> [T] {
guard let first = self.first as? T else { return [] }
return Array(self.dropFirst()).scanl(initial: first, combine: combine)
}
}
The fact that Iterator.Element
and T
needn't necessarily be of the same type is apparent if you construct an example that scans an array of one type to construct an array of another type, e.g.
/* scant [Int] array to construct [String] array */
let foo = [1, 2, 3, 4, 5]
let bar = foo.scanl(initial: "0") { String($0) + $1 }
print(bar) // ["0", "10", "210", "3210", "43210"]
If you'd only like your scanl
method and its collector to produce same-type arrays (as the one being scanned), then you needn't include a generic T
, but could use Iterator.Element
type in place of T
in your extensions above.