I have example code:
def test = {
val l : Seq[(String, String)] = Seq()
val foo : (String, String) => Unit = {case (a, b)=>}
l.foreach[Unit](foo)
}
It gives me the next error:
Error:(8, 21) type mismatch;
found : (String, String) => Unit
required: ((String, String)) => Unit
l.foreach[Unit](foo)
As far as I understand foreach has a type (A=>U)=>Unit where:
A is template parameter of my collection and
U is template parameter of foreach itself
My question is why is ((String, String)) => Unit required? Where do the extra brackets come from?
If you check in the REPL, you'll see that foo is a <function2>, that is, a function that takes 2 argument:
scala> val foo : (String, String) => Unit = {case (a, b)=>}
foo: (String, String) => Unit = <function2>
.foreach however expects a function that takes a single arguement (of type A), which in your case is a Tuple2.
If you set foo to be a <function1>, then it works:
scala> val foo : ((String, String)) => Unit = {case (a, b)=>}
foo: ((String, String)) => Unit = <function1>
scala> val l : Seq[(String, String)] = Seq()
l: Seq[(String, String)] = List()
scala> l.foreach[Unit](foo)
scala>
Let's start from top.
You have
val l: Seq[(String, String)]
that is a Seq of tuples of two strings. So each of the elements of l is of type (String, String) which is a syntactic sugar for Tuple2[String, String].
Now you have
val foo: (String, String) => Unit
that is a function of two arguments each being String. Again, the type signature above is syntactic sugar for Function2[String, String, Unit].
Considering the above your code can be rewritten as follows:
def test = {
val l: Seq[Tuple2[String, String]] = Seq()
val foo: Function2[String, String, Unit] = {case (a, b)=>}
l.foreach[Unit](foo)
}
foreach expects a single argument function, i.e. a Function1[T, R], thus the type mismatch.
The type definition foo: (String, String) => Unit says that foo is a function which takes two parameters of type String. However, your sequence l: Seq[(String, String)] contains tuples of type type t = (String, String). Thus, calling l.foreach expects a function which is applicable to the tuple type t. Thus, it expects a function of type t => Unit, which is equivalent to ((String, String)) => Unit.
Related
I'd like to dynamically insert a type parameter, i.e. List[T], where T can only be found at run-time.
Normally you can create bindings like this if you already have an existing type parameter T (not the case), or during run-time using TypeTags.
The latter sounds like the way to go, but this shifts the question to "how do I get my TypeTag here".
I know how to create a TypeTag using if you have your type T (typeTag[T]), or if you have an instance of your type T (see getTypeTag below).
However, I have neither; what I do have of my type in question is a reflect.runtime.universe.Type. Might it be possible to convert this into a TypeTag so I can dynamically insert my type parameter?
Bonus points if the List can be made dynamic as well.
scala> import scala.reflect.runtime.{universe => ru}
scala> def getTypeTag[T: ru.TypeTag](obj: T) = ru.typeTag[T]
scala> def insertTag[T](tt: ru.TypeTag[T]) = List[T]_
scala> val fn = (a: String) => "foo"
fn: String => String = <function1>
scala> val pars = getTypeTag(fn).tpe.typeArgs.init(0)
pars: reflect.runtime.universe.Type = String
scala> insertTag(pars)
<console>:21: error: type mismatch;
found : reflect.runtime.universe.Type
required: reflect.runtime.universe.TypeTag[?]
insertTag(pars)
^
I haven't figured out how to convert a Type to TypeTag. If your goal is to get TypeTag just for function parameters, you can modify your function getTypeTag to accept functions:
import scala.reflect.runtime.{universe => ru}
def getTypeTag[T: ru.TypeTag](obj: (T) => Any) = ru.typeTag[T]
def insertTag[T](tt: ru.TypeTag[T]) = List[T] _
val fn = (a: String, b: Int) => "foo"
var parTypeTag = getTypeTag(fn.tupled)
insertTag(parTypeTag) // Seq[(String, Int)] => List[(String, Int)] = <function1>
I am new to Scala. This is the code that I have written.
object Main extends App {
val mp: Map[String, String] = Map[String, String]("a"->"a", "b"->"b", "c"->"c", "d"->"d")
val s: Option[(String, String)] = mp.find((a: String, b: String) => {
if(a == "c" && b == "c") {
true
}
else {
false
}
})
println(s)
}
I am getting the following error.
error: type mismatch;
found : (String, String) => Boolean
required: ((String, String)) => Boolean
What am I doing wrong?
You need to change
mp.find((a: String, b: String) =>
to either
mp.find(((a: String, b: String)) =>
or
mp.find( case (a: String, b: String) =>
What you have coded is a function expecting two parameters, but you will only be passing in one, which is a Pair (also called Tuple2). The extra braces and the case keyword are ways of specifying that you are only passing in the one parameter, which is an instance of a Pair.
The problem is that find expects a function that takes a single argument, a Tuple2 in this case and returns a Boolean: ((String, String)) => Boolean. However, what you have there is a function that takes two args a and b, not a tuple (brackets matter): (String, String) => Boolean.
Here is one way to fix it. In this case I use pattern matching to extract arguments:
object Main extends App {
val mp: Map[String, String] = Map[String, String]("a"->"a", "b"->"b", "c"->"c", "d"->"d")
val s: Option[(String, String)] = mp.find{ case(a, b) => a == "c" && b == "c" }
println(s)
}
alternatively you could also do:
val s: Option[(String, String)] = mp.find(t => t._1 == "c" && t._2 == "c")
Either would print:
Some((c,c))
Forgive me if this question is a duplicate; I'm having trouble finding anything because I don't know the right words to search. So, with implicit def, I can do things like this:
type CharsetMap = Map[Charset, Byte]
implicit def seqtup2CharsetMap(input: Seq[(String, Int)]): CharsetMap = {
Map.empty // placeholder
}
def somef(a: Int, b:Int, p: CharsetMap) = p
somef(1, 3, Seq(("hey", 2), ("there", 9)))
which lets me call somef with a Seq[(String, Int)] object as a parameter. The problem is that I have something like this...
def somef2(p: (CharsetMap) => Int) = p
and this does not work:
val p = (a: Seq[(String, Int)]) => 19
somef2(p)
How can I do this without doing an implicit def specifically for (Seq[(String, Int)]) => Int?
It looks like you want to implicitly convert some function A => B to a function that goes from C => B. You can do that with this generic implicit:
implicit def f2InputConverter[A, B, C](f: A => B)(implicit i: C => A): C => B = (c: C) => f(i(c))
Once you have that in scope, in your particular case, you'll need an implicit function which is the inverse of the one that you've defined in the question:
implicit def charsetMap2Seqtup(input: CharsetMap): Seq[(String, Int)] = {
Nil // placeholder
}
and then you should be able to call somef2 with p
I've been using scala for a while now and I thought I was really starting to understand everything (well, most things...), but I found myself confused by a number of the method definitions in the Map class. I know how foldLeft, etc work, but what I'm confused about is the type parameters used in the Map functions. Let's use foldLeft as an example:
foldLeft [B] (z: B)(op: (B, (A, B)) ⇒ B) : B
The definition for the Map trait itself takes two type parameters 'A' and 'B' (e.g. Map[A,+B]). From what I can tell, when you define a type parameter for a method using the same name as one of the type parameters for the class/trait, it overrides the class/trait value. Take this definition of Foo as an example:
class Foo[A : Manifest, B : Manifest] {
def isAString() = manifest[A] == manifest[String]
def isAInt() = manifest[A] == manifest[Int]
def isBString() = manifest[B] == manifest[String]
def isBInt() = manifest[B] == manifest[Int]
def nowIsBString[B : Manifest] = manifest[B] == manifest[String]
}
scala> val f = new Foo[String,Int]
f: Foo[String,Int] = Foo#7bacb41
scala> f.isAString
res290: Boolean = true
scala> f.isAInt
res291: Boolean = false
scala> f.isBString
res292: Boolean = false
scala> f.isBInt
res293: Boolean = true
scala> f.nowIsBString[String]
res294: Boolean = true
scala> f.nowIsBString[Int]
res295: Boolean = false
So in the foldLeft definition, 'B' comes from the method definition and 'A' comes from the trait definition. For example:
val xm = Map("test" -> 1, "test2" -> 2)
scala> val foldFn = (z: Int, kv: (String, Int)) => z + kv._2
foldFn: (Int, (String, Int)) => Int = <function2>
scala> m.foldLeft(0)(foldFn)
res298: Int = 3
This is as expected as 'B' for the function matches 'B' for the trait, but what if I change the 'B' type for the function to String instead of Int:
scala> val foldFn = (z: String, kv: (String, String)) => z + kv._2
foldFn: (String, (String, String)) => java.lang.String = <function2>
scala> m.foldLeft("")(foldFn)
<console>:19: error: type mismatch;
found : (String, (String, String)) => java.lang.String
required: (java.lang.String, (java.lang.String, Int)) => java.lang.String
m.foldLeft("")(foldFn)
So let's change the kv parameter to (String, Int):
scala> val foldFn = (z: String, kv: (String, Int)) => z + kv._2
foldFn: (String, (String, Int)) => java.lang.String = <function2>
scala> m.foldLeft("")(foldFn)
res299: java.lang.String = 12
Unlike my Foo example, in this case the Map's 'B' value is taking precedence over the functions definition, but only for the kv parameter. What I would have expected is to see a foldLeft defined as follows:
foldLeft[C] (z: C)(op: (C, (A, B)) => C): C
That would be more clear to me, but it is not defined this way. So does anyone know the rules for when a methods parameter will override a trait/class parameter and when it will not?
Scala is the same as Java in this respect, and the following from the "Names" chapter of the Java specification applies:
A declaration d of a type named n shadows the declarations of any
other types named n that are in scope at the point where d occurs
throughout the scope of d.
So the type parameter for a method will always shadow a class or trait type parameter with the same name. Your Foo example demonstrates this fact.
The apparent counterexample you're seeing in the case of Map's foldLeft is just an unpleasant artifact of the current version of Scaladoc, as is pointed out in the answers to the question you've linked. foldLeft isn't defined in the Map trait, but in TraversableOnce, where there isn't a trait type parameter named B at all.
In general shadowing the type parameter of a trait or class in a method is a really bad idea, of course.
I am trying to define a Map literal with key: String, value: (Any)=>String. I tried the following, but get a syntax error:
def foo(x: Int): String = /...
def bar(x: Boolean): String = /...
val m = Map[String, (Any) => String]("hello" -> foo, "goodbye" -> bar)
Funny that no one actually gave a type that would work. Here's one such:
def foo(x: Int): String = x.toString
def bar(x: Boolean): String = x.toString
val m = Map[String, (Nothing) => String]("hello" -> foo, "goodbye" -> bar)
The reason why it works this way is because Function1 is contra-variant on the input, so (Nothing) => String is a superclass of (Int) => String. It is also co-variant on the output, so (Nothing) => Any would be a superclass to any other Function1.
Of course, you can't use it like that. Without manifests, you can't even uncover what the original type of Function1 is. You could try something like this, though:
def f[T : Manifest](v: T) = v -> manifest[T]
val m = Map[String, ((Nothing) => String, Manifest[_])]("hello" -> f(foo), "goodbye" -> f(bar))
val IntManifest = manifest[Int]
val BooleanManifest = manifest[Boolean]
val StringManifest = manifest[String]
m("hello")._2.typeArguments match {
case List(IntManifest, StringManifest) =>
m("hello")._1.asInstanceOf[(Int) => String](5)
case List(BooleanManifest, StringManifest) =>
m("hello")._1.asInstanceOf[(Boolean) => String](true)
case _ => "Unknown function type"
}
Int => String is not a subclass of Any => String, rather, the contrary. You can't put (replace) an Int => String function when a code expects Any => String, since that code can apply the function with, say, "hi".
#Ben suggestion works, but how is it useful? you can't invoke the function once you get it from the Map.
If you really want to do this, maybe define foo as a partial function:
val foo: PartialFunction[Any, String] = {case i: Int => ....}
Obviously, this will fail at runtime if you pass it a string, but you can always test if the function is ok for use with your parameter by using isDefinedAt. (another alternative may be manifests, but I don't see the value here)
If I let the compiler infer it I seem to get an illegal type:
scala> val m = Map("hello" -> foo _, "goodbye" -> bar _)
m: scala.collection.immutable.Map[java.lang.String,(Boolean with Int) => String] =
Map((hello,<function1>), (goodbye,<function1>))
scala> m("hello")(8)
<console>:9: error: type mismatch;
found : Int(8)
required: Boolean with Int
m("hello")(8)
scala> var q = new Boolean with Int
<console>:5: error: illegal inheritance from final class Boolean
var q = new Boolean with Int
Anyway, what you want is not the type Any but a generic of "any type" which is _:
scala> val mm = Map[String, (_) => String]("hello" -> foo _, "goodbye" -> bar _)
mm: scala.collection.immutable.Map[String,Function1[_, String]] =
Map((hello,<function1>), (goodbye,<function1>))
I just posted a question about how to invoke such functions because I don't actually know.
Trait Function1 is contravariant for parameter, so def foo(x: Int): String is not a (Any) => String. So the following would work:
scala> def baz(x: Any): String = "baz"
baz: (x: Any)String
scala> val m2 = Map[String, (String) => String]("hello" -> baz)
m2: scala.collection.immutable.Map[String,(String) => String] = Map((hello,<function1>))
This is how I did it to fulfill a similar requirement.
object MapToMethods {
private def increment(x: Int): Int = x+1
private def decrement(x: Int): Int = x-1
val m: Map[String, Int => Int] =Map("increment" -> increment, "decrement" ->decrement)
println(m("increment")(2)) //prints 3
println(m("decrement")(3)) //prints 2
}