Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

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

scala - Type inference fails on Set made with .toSet?

Why is type inference failing here?

scala> val xs = List(1, 2, 3, 3)
xs: List[Int] = List(1, 2, 3, 3)

scala> xs.toSet map(_*2)
<console>:9: error: missing parameter type for expanded function ((x$1) => x$1.$times(2))
       xs.toSet map(_*2)

However, if xs.toSet is assigned, it compiles.

scala> xs.toSet
res42: scala.collection.immutable.Set[Int] = Set(1, 2, 3)

scala> res42 map (_*2)
res43: scala.collection.immutable.Set[Int] = Set(2, 4, 6)

Also, going the other way, converting to Set from List, and mapping on List complies.

scala> Set(5, 6, 7)
res44: scala.collection.immutable.Set[Int] = Set(5, 6, 7)

scala> res44.toList map(_*2)
res45: List[Int] = List(10, 12, 14)
Question&Answers:os

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

1 Reply

0 votes
by (71.8m points)

Q: Why doesn't toSet do what I want?

A: That would be too easy.

Q: But why doesn't this compile? List(1).toSet.map(x => ...)

A: The Scala compiler is unable to infer that x is an Int.

Q: What, is it stupid?

A: Well, List[A].toSet doesn't return an immutable.Set[A]. It returns an immutable.Set[B] for some unknown B >: A.

Q: How was I supposed to know that?

A: From the Scaladoc.

Q: But why is toSet defined that way?

A: You might be assuming immutable.Set is covariant, but it isn't. It's invariant. And the return type of toSet is in covariant position, so the return type can't be allowed to be invariant.

Q: What do you mean, "covariant position"?

A: Let me Wikipedia that for you: http://en.wikipedia.org/wiki/Covariance_and_contravariance_(computer_science) . See also chapter 19 of Odersky, Venners & Spoon.

Q: I understand now. But why is immutable.Set invariant?

A: Let me Stack Overflow that for you: Why is Scala's immutable Set not covariant in its type?

Q: I surrender. How do I fix my original code?

A: This works: List(1).toSet[Int].map(x => ...). So does this: List(1).toSet.map((x: Int) => ...)

(with apologies to Friedman & Felleisen. thx to paulp & ijuma for assistance)

EDIT: There is valuable additional information in Adriaan's answer and in the discussion in the comments both there and here.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...