I've got a function that expects a Tuple2, where one item must be a long. When I attempt to pass pairs with literal numbers using the -> implicit, they are being interpreted as Int instead of Long.
Here, the problem is demonstrated:
scala> val x: (Long, String) = (5, "test")
x: (Long, String) = (5,test)
scala> val x: (Long, String) = 5L -> "test"
x: (Long, String) = (5,test)
scala> val x: (Long, String) = 5 -> "test"
<console>:43: error: type mismatch;
found : (Int, String)
required: (Long, String)
val x: (Long, String) = 5 -> "test"
I suppose the problem is that when the implicit is applied, type inference locks in on Int, but in the first example, type inference is nice enough to consider the number a Long.
But my DSL works much better if I can use -> and omit the L suffix. Is there a way to achieve this?
Unfortunately, Int is not formally a subtype of Long. Thus, an (Int, String) can not be passed where a (Long, String) is expected, despite the fact that Tuple2 is covariant in its type parameters.
However, Int is viewable as Long. So, you can design a function that will upconvert an Int to a Long the following way:
scala> def goodFunc[LongLike <% Long](arg: (LongLike, String)) = { "whatevs" }
goodFunc: [LongLike](arg: (LongLike, String))(implicit evidence$1: LongLike => Long)String
scala> goodFunc(5 -> "test")
res4: String = whatevs
Or, better yet, use:
def goodFunc[LongLike](arg: (LongLike, String))(implicit ev: LongLike => Long) = { "whatevs" }
, since <% is deprecated.
Related
Consider the following code snippet:
def foo(a: Int)(b: Int) = a + b
foo
It does not compile, and produces the following error message:
error: missing argument list for method foo
Unapplied methods are only converted to functions when
a function type is expected.
You can make this conversion explicit by writing
`foo _` or `foo(_)(_)` instead of `foo`.
The foo _ hint works. But if I write the expression
foo(_)(_)
as suggested by the previous error message, I get a new error message:
error: missing parameter type for expanded
function ((x$1: <error>, x$2: <error>) => foo(x$1)(x$2))
This seems rather counterintuitive.
Under what circumstances is the foo(_)(_)-hint supposed to be helpful, what exactly does it tell me?
(noise removed; the more I kept editing the question, the less sense did it make; Kolmar is right)
The type of foo(_)(_) is (Int, Int) => Int. So it works if you specify that type or use it in the context that expects this type:
scala> foo(_: Int)(_: Int)
res1: (Int, Int) => Int = $$Lambda$1120/1321433666#798b36fd
scala> val f: (Int, Int) => Int = foo(_)(_)
f: (Int, Int) => Int = $$Lambda$1121/1281445260#2ae4c424
scala> def bar(f: (Int, Int) => Int): Int = f(10, 20)
bar: (f: (Int, Int) => Int)Int
scala> bar(foo(_)(_))
res2: Int = 30
I have a function, and would like to obtain its parameter types and return type for use in Scala macros.
scala> val fn = (a: String, b: Double) => 123
fn: (String, Double) => Int = <function2>
scala> fn.getClass
res1: Class[_ <: (String, Double) => Int] = class $anonfun$1
In the above example, the parameter types and return type already get printed at both lines, but I don't know how to access them. Even with toString I'd be stuck with the <function2> and class $anonfun$1 parts right of the = sign -- otherwise a bit of ugly string parsing might have done.
I found that the MethodSymbolApi offers a way to extract this information for methods, but it seems like this might not help for this particular case.
I'm currently looking into AST parsing (as part of scala.meta) to extract the information, but I'd think this question would seem basic enough to be covered by the standard reflection library, though I've failed to find what I want in there. Any ideas?
Edit based on #johanandren's answer:
I haven't found a neater way to extract them from the TypeTag/Type yet, but this does already work. :)
scala> val fn = (a: String, b: Double) => 123
scala> import scala.reflect.runtime.{universe => ru}
scala> def getTypeTag[T: ru.TypeTag](obj: T) = ru.typeTag[T]
scala> getTypeTag(fn).tpe.toString.split(" => ")
res179: Array[String] = Array((String, Double), Int)
getClass is part of the Java reflection API which does not quite understand Scala types, you should look at the Scala Reflection API instead. This should get you started, http://docs.scala-lang.org/overviews/reflection/overview.html
Not sure but I think a TypeTag for the function type is what you want.
Just for completness, when you are in Scala REPL, you can access the type as:
scala> val fn = (a: String, b: Double) => 123
fn: (String, Double) => Int = <function2>
scala> :type fn
(String, Double) => Int
At runtime, Scala compiler won't have complete type information. So it forms a code snippet fn, ( also does its own symbol table lookups ).
https://github.com/scala/scala/blob/v2.10.5/src/compiler/scala/tools/nsc/interpreter/ILoop.scala#L449
Then passes it to the compiler which then attaches the type information to an implicit evidence type.
( explained here I want to get the type of a variable at runtime )
scala> import scala.reflect.runtime.universe.{TypeTag, typeTag}
import scala.reflect.runtime.universe.{TypeTag, typeTag}
scala> def getTypeTag[T: TypeTag](obj: T) = typeTag[T]
getTypeTag: [T](obj: T)(implicit evidence$1: reflect.runtime.universe.TypeTag[T])reflect.runtime.universe.TypeTag[T]
Now we have an evidence that will give us the exact type information:
scala> getTypeTag(fn)
res0: reflect.runtime.universe.TypeTag[(String, Double) => Int] = TypeTag[(String, Double) => Int]
scala> val targs = res0.tpe.typeArgs
targs: List[reflect.runtime.universe.Type] = List(String, Double, Int)
Now we can access the types with ease:
scala> val (in, out) = (ta.init, ta.last)
in: List[reflect.runtime.universe.Type] = List(String, Double)
out: reflect.runtime.universe.Type = Int
scala> println(s"INPUTS: $in")
INPUTS: List(String, Double)
scala> println(s"OUTPUT: $out")
OUTPUT: Int
I'm fairly new to Scala and functional programming in general so I'm having a bit trouble wrapping my head around the concept of partially applied functions and function currying. There's also a pretty high chance that I'm gonna mix up some terminology, so all corrections are appreciated.
Note: I'm using the Scala Play framework but this is more of a Scala problem than a Play problem.
Given a function like this
def create(id: Long, userId: Long, label: String)
I get the userId and label as a (Int, String) tuple and the id as a Long. Basically what I'm trying to do is passing the id and the tuple to the function at the same time.
Now, I've read that passing a tuple to a function can be done something like this
scala> def f(a: Int, b: String) = 0
f: (a: Int, b: String)Int
scala> (f _).tupled((2, "Hello"))
res0: Int = 0
and that it is also possible to partially apply a function like this
scala> def f(a: Int, b: String) = 0
f: (a: Int, b: String)Int
scala> val ff = f(_: Int, "Hello")
ff: Int => Int = <function1>
scala> ff(2)
res1: Int = 0
So my initial idea was to combine these two concepts something like this
scala> def g(a: Long, b: Int, c: String) = 0
g: (a: Long, b: Int, c: String)Int
scala> val h = g(1, _: Int, _: String)
h: (Int, String) => Int = <function2>
scala> (h _).tupled((2, "Hello"))
However this results in an error
<console>:10: error: _ must follow method; cannot follow h.type
(h _).tupled((1, "Hello"))
^
So my question is first of all why doesn't this work because to me this makes sense. And secondly how would I go about achieving this effect?
Thanks for your help!
Just don't abstract it twice: don't do redundand underscore to the h as it's already a function after partial-applying:
scala> def create(a: Long, b: Int, c: String) = 0
create: (a: Long, b: Int, c: String)Int
scala> val h = create(1, _: Int, _: String)
h: (Int, String) => Int = <function2>
scala> h.tupled((1, "Hello"))
res0: Int = 0
More deeply, tupled is defined on functions (means object of Function, like Int => String), not on methods (like def f(i: Int): String) - so sometimes you need to convert a method to the function - it's called eta-expansion (or eta-abstraction more generally). When you do partial applying - eta-expansion is done automatically (you already have a (Int, String) => Int) - so you don't have to do it twice.
See The differences between underscore usage in these scala's methods, Difference between method and function in Scala for more information.
found : (Int, String, Option[java.lang.String])
required: (Int, String, Option[java.lang.String])
Pertinent code:
object M extends Table[(Int, String, Option[String])]("table") {
def msaid = column[Int]("msaid", O NotNull)
def name = column[String]("name", O DBType "varchar(255)")
def shape = column[Option[String]]("shape")
def * = msaid ~ name ~ shape
type T = (Int, String, Option[java.lang.String])
def apply(msa: T) = 1
def q() = db withSession { s: Session => (for (r <- M) yield M(*)).list()(s) }
^
^
...
I've also tried
type T = (Int, String, Option[String])
The ultimate goal is that I want all the selected columns to converted into an Object with named accessors, instead of being a tuple.
Scala version 2.9.2 (Java HotSpot(TM) 64-Bit Server VM, Java 1.7.0_07).
UPDATE:
Here's a Gist of the issue (slightly simplified from the above code and eliminates any String/java.lang.String "confusion" by using only Int.)
The error message didn't use to tell you which was the TupleN, though I think that was improved at some point. The mismatch is between a tuple and n args. Or not.
The fix is in 2.9.2. I notice your .sbt uses 2.9.1 scalaquery, in case that matters. And isn't scala-tools.org obsolete? Sorry for half-helping.
Speaking as a non-user, it looks like a Projection2 is not the Tuple you seek, albeit a Product:
class Projection2 [T1, T2] extends (Column[T1], Column[T2]) with Projection[(T1, T2)]
REPLing:
scala> M.column[Int]("id") ~ M.column[Int]("n")
res1: (Int, Int) = Projection2
scala> M(res1)
<console>:23: error: type mismatch;
found : (Int, Int)
required: (Int, Int)
M(res1)
^
scala> M.apply
def apply(v: (Int, Int)): Int
scala> M.apply((1,2))
res3: Int = 1
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
}