Implicitly converting map to function

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,
Edge(2,3)->1,
Edge(3,4)->1,
Edge(4,6)->5,
Edge(4,5)->1,
Edge(5,6)->1)

val Some(Path(vertices,edges)) = g.shortestPath(1,6,(weight.apply _))
println(s"vertices=\$vertices edges=\$edges")
}
``````
1 Like

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…

1 Like

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.

1 Like

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>
``````
2 Likes

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.