Dima Lituiev
Dima Lituiev

Reputation: 13136

functions as values of Map in scala

I am trying to create a map of lambda functions in Scala

val identity = ((x:Any) => x)
val propmap = Map("references-count" -> identity, 
    "title" -> ((x:List[String]) => x(0)),
    "score" -> identity,
    "issued" -> ((x:List[Any]) => x(0)))

when I type propmap("score") or propmap("title") the output I get is the same: <function1>.

Running identity(10.1) returns the expected result. However

val f1 = propmap("score") f1(10.9)

results in:

Name: Unknown Error
Message: <console>:29: error: type mismatch;
 found   : Double(10.9)
 required: List[String]
       f1(10.9)
          ^
StackTrace: 

Seemingly the function is overwritten. Where to go for the besung immutabilty?

Upvotes: 0

Views: 308

Answers (2)

Assaf Mendelson
Assaf Mendelson

Reputation: 13001

The problem is the type of propmap.

Scala infers the type as String, (List[String] => Any)

The reason for that is that scala needs to infer a type which matches ALL values. The String as key is obvious but for the function, it needs to find a function type which matches all functions. Since all functions have 1 parameter this would be function1.

If you look at the definition of function1 you would see it is:

trait Function1[-T1, +R] extends AnyRef

This means that it needs to find the first type to be the most constrictive. In this case this is List[String] and therefore it expects a function List[String]=>Any (this actually makes sense because you want a type you can use on ALL functions).

So scala automatically converts your identity function to be (x: List[String] => x) in practice and therefore when you try to pass it a number it fails.

Possible solutions:

The first solution as mentioned by @KotWarm would be to use asInstanceOf:

val f1 = propmap("score").asInstanceOf[Any ⇒ Any]
println(f1(10.9))

The second solution would be to rewrite the functions to use Any, for example:

val propmap = Map("references-count" -> identity,
                  "title" -> ((x: Any) => x.asInstanceOf[List[String]](0)),
                  "score" -> identity,
                  "issued" -> ((x: Any) => x.asInstanceOf[List[Any]](0)))

Upvotes: 2

KosWarm
KosWarm

Reputation: 626

Because scalac determined the type of collection as

propmap: scala.collection.immutable.Map [String, List [String] => Any]

Determine the type of your collection explicitly so that the compiler knows what you want to get

Here is an example code

    val identity = ((x:Any) => x)
    val propmap = Map[String,_ => _]("references-count" -> identity,
        "title" -> ((x:List[String]) => x(0)),
        "score" -> identity,
        "issued" -> ((x:List[Any]) => x(0)))

But to execute the methods you must cast the type

    val f1 = propmap("score").asInstanceOf[Any ⇒ Any]
    println(f1(10.9))

Upvotes: 1

Related Questions