Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
548 views
in Technique[技术] by (71.8m points)

swift - What is the cause of this type error?

Two questions:

  1. Why does this code fail to compile? I believe (but am not 100% sure, I may have made a mistake) that it's type-correct.

  2. What does the error message mean? I'm confused why the expected argument type is _ -> _ (or maybe I just don't know what it means by _ -> _ in this case). The goal of this question is to learn how to correctly diagnosis this error message, should I run into it again in the future.

The code:

This code fails to compile with the error message "Cannot convert value of type 'A -> B' to expected argument type '_ -> _':

class ZipList<A> {
    let xs: [A]
    init(xs: [A]) {
        self.xs = xs
    }
    func map<B>(f: A -> B) -> ZipList<B> {
        return ZipList(xs: self.xs.map(f))
    }
}

enter image description here

Additional information:

At first, I assumed the problem was with type inference, so I tried writing out the types explicitly, but that also failed:

enter image description here

enter image description here

However, this compiles just fine (the only difference from my original map version is the <B> passed to the ZipList initializer):

func map4<B>(f: A -> B) -> ZipList<B> {
    return ZipList<B>(xs: self.xs.map(f))
}
See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

The problem is that when you don't explicitly supply the generic parameter type of ZipList when you refer to it, the compiler will try and infer it for you – which it doesn't always get correct.

As you're already inside a ZipList<A> class, the compiler will try and infer ZipList to be ZipList<A> when you omit the generic parameter (see this question for more info about this behaviour).

Therefore it's now expecting an input of [A] in the ZipList(xs:_) initialiser, meaning that the map function is inferred to be A -> A, which you're trying to pass A -> B to, causing the type mismatch (this is why f is highlighted as the problem in your error).

If you simplify down your example to just calling init() on your ZipList without providing an argument, you'll see a more helpful error message:

class ZipList<A> {

    init() {}

    func map<B>() -> ZipList<B> {
        // error: Cannot convert return expression of type 'ZipList<A>' to 'ZipList<B>'
        return ZipList() 
    }
}

The fact that the compiler completely ignores the explicit type annotation of the return for the map() method is a bug and is tracked by SR-1789. The cause, as described by Jordan Rose in the comments of the report is that:

It seems to be a case of us eagerly assuming the parameters are the same as for self. (That's usually a feature, but not when it gets in the way of other inference.)

The solution, as you've already found, is to explicitly state the generic parameter type of ZipList when you create a new instance:

return ZipList<B>(xs: xs.map(f))

This forces the generic parameter to be of type B, therefore preventing Swift from incorrectly inferring it, allowing the map function to resolve.

As for what the error message "Cannot convert value of type 'A -> B' to expected argument type '_ -> _" means, _ in this case simply refers to a generic type which the compiler cannot resolve (not a helpful error message, I know). So all the compiler is telling you is that it was expecting a function that takes an input of an unknown type, and returns that same type.

It often helps when diagnosing these kind of error messages to split the expression up into multiple sub-expressions and inspect the types for each those to try and find the mis-match. It can also help to begin simplifying the example down (like using init() instead of init(xs:[A]) in your map method), until you run into a more helpful error message.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...