Here’s problem I’ve encountered several times. If I have a function which has a parameter of the form A=>B, but I have a Map[A,B], why can’t I pass that instead? Likewise if I have an object X with an
apply method of type A=>B. In the case of an object, I can pass (X _). But If I try the same thing with a map, I get an all too expected error.
Error:(52, 60) _ must follow method; cannot follow scala.collection.immutable.Map[lecture.graph.Edge[Int],Int]
val Some(Path(vertices,edges)) = g.shortestPath(1,6,(weight _))
Turns out I can use
(weight.apply _) and everyone is happy. Is that what I’m supposed to be doing? Seems obscure. On the other hand, it’s not much typing.
val weight = Map(Edge(1,3)->1,
val Some(Path(vertices,edges)) = g.shortestPath(1,6,(weight.apply _))
Something worth noting here:
Map is actually a
PartialFunction, so if your target function was expecting
A => Option[B], you could simply use
weight.lift and it would work.
But in this case, I think your
weight.apply is about the best you can do, because you’re being a bit unsafe. (At least from the type perspective.) That’s because the
Map might not contain the target key, and thus it might throw an Exception.
That’s why there’s no built-in for this and you have to spell it out. You may have outside knowledge that the
Map is complete, but the compiler has no way of knowing that…
That’s right. The fact that you can’t directly use a
Map[A, B] as a function
A => B is an implementation detail, a consequence of how the
Map trait is declared:
trait Map[K, +V] extends Iterable[(K, V)] with GenMap[K, V] with MapLike[K, V, Map[K, V]]
I.e. it doesn’t inherit from
A => B therefore can’t be upcast to it.
Confusion. Maps are functions.
@ val a: Int => String = Map(1 -> "x")
a: Int => String = Map(1 -> "x")
@ Set(1, 2, 3).map(Map(1 -> "x", 2 -> "y", 3 -> "z"))
res6: Set[String] = Set("x", "y", "z")
@ implicitly[Map[Int, String] <:< (Int => String)]
res7: Map[Int, String] <:< Int => String = <function1>
Yup, you’re right. I didn’t look hard enough!
Map[K, V] indeed has supertype
K => V.
In fact I just went and double-checked @jimka’s issue, but it seems to be working for me:
scala> def f(x: Int, g: Int => String): String = g(x)
f: (x: Int, g: Int => String)String
scala> f(1, Map(1 -> "a"))
res1: String = a
Perhaps you’re running an older Scala version, @jimka? Although I don’t see it making much of a difference outside of bugfixes.
Remarkable. It works for me as well. Thanks for the help. But it sounds like this feature is also a surprise to some experts as well as beginners.
… huh. For some reason, that’s not showing very obviously in the Scaladocs.
PartialFunction comes in through
MapLike, which is what I had found.
Function1 seems to be getting pulled in via
GenMapLike, but the Scaladoc for the latter doesn’t actually say that. Odd – I’m clearly missing a subtlety here…
Look at the ‘Linear Supertypes’ section, it’s listed there among a long list of other supertypes.
What’s a “linear supertype” BTW? Are there any other kind of supertypes?
I think it just means ‘a linear list view of the supertype graph’.
Oh man, now I’m thinking. Are there probabilistic type systems?
val a: Long0.99 = 3L
val b: Long0.99 = 4L
val c: Long1.00 = a * b
would compile 98.01% of the time.
Seems like this could have an application to NLP.