I know how to define a method with variable length argument:
case class taxonomy(vocabularies:(String,Set[String])*)
and client code is very clean:
val terms=taxonomy("topics"->Set("economic","politic")
,"tag"->Set("Libya","evolution")
)
but I want to Know how can I use this case class when I have a variable (instead of a Sequence of variable) like this:
val notFormattedTerms = Map("topics"->Set("economic","politic")
,"tag"->Set("Libya","evolution"))
taxonomy(notFormattedTerms.toSeq:_*)
With : _* you virtually transform a sequence argument so that it looks as if a several arguments had been passed to the variable length method. This transformation, however, only works for (ordered?) simple sequence types and, as in this case, not for a Map. Therefore, one will have to use an explicit toSeq before.
Related
Why call to method whose all parameters has default values is not the same than calling a method without parameter in scala?
Example:
scala> def a(a:Int=1)=print(a)
a: (a: Int)Unit
scala> def b=print(1)
b: Unit
scala> a
<console>:13: error: missing argument list for method a
Unapplied methods are only converted to functions when a function type
is expected.
You can make this conversion explicit by writing `a _` or `a(_)`
instead of `a`.
a
^
scala> b
1
However
scala>a()
1
works ok.
Shouldn't be the same call?
Scala enable Arity-0(a) method to omit parentheses.
https://docs.scala-lang.org/style/method-invocation.html#arity-0
I can think of at least one problem caused by not needing to write parenthesis. Consider the following:
val xs = List(1, 2, 3, 4)
def myFunc(x: Int = 42) = 2 * x
val ys = xs.map(myFunc)
Eta expansion is happening in my example, method is lifted into function. But if it was possible to invoke function with default parameters this way, syntax would be ambigous at least in this case. (I know that here invocation would lead to wrong argument type of map function, so in theory it is possible to resolve this ambiguity here, but it would mean that type of expression would have impact on the syntax interpretation, which is handled before type-checking in any language i know)
If you don't add a parenthesis after a, that will have several meanings.
a(): Unit
a(_): Int => Unit
Which one do you mean? Hence it force you to add parenthesis.
In Scala, a method can have zero or more parameter lists, each of which has zero or more parameters. If you want to call a method, you have to supply matching argument lists with matching arguments to the parameters and parameter lists.
In your case, you defined the method with one parameter list, ergo you need to call it with one argument list.
Shouldn't be the same call?
No, they are not the same. The first call has zero argument lists, the second call has one argument list. That's different.
There are some cases where Scala lets you call methods with a single empty parameter list by supplying no argument lists. The reason for this is simple convenience: you want to call Java getters (which are defined with an empty parameter list) the same way as Scala getters (which are defined without a parameter list). But, this doesn't work in general.
I have a method called getAge(timestamp:Long) and I want to register this as a sql function.
I have
sqlContext.udf.register("getAge",getAge)
But its telling me I need arguments or use _ afterwards, I tried using _ but gives me error. How do I register it with an argument. I am new to scala so I have no idea how to do this.
sqlContext.udf.register("getAge",getAge)
should be:
sqlContext.udf.register("getAge",getAge _)
The underscore (must have a space in between function and underscore) turns the function into a partially applied function that can be passed in the registration.
More explanation
When we invoke a function, we have to pass in all the required parameters. If we don't, the compiler will complain.
We can however ask it for the function as a value, with which we can pass in the required parameters at a later time. How we do this is to use the underscore.
getAge means to run getAge - for example, def getAge = 10 giving us 10. We don't want the result, we want the function. Moreover, with your definition, the compiler sees that getAge requires a parameter, and complains that one wasn't given.
What we want to do here is to pass getAge as a function value. We tell Scala, we don't know the parameter yet, we want the function as a value and we'll supply it with the required parameter at a later time. So, we use getAge _.
Assuming signature for getAge is:
getAge(l: Long): Long = <function>
getAge _ becomes an anonymous function:
Long => Long = <function>
which means it needs a parameter of type Long and the result of invoking it will yield a value of type Long.
We know that scala does not support more than 22 params, but if i write this
def echo(args: String*) = for (arg <- args) println(arg)
we can use more than 22 params to call this function like this.
echo("1","1","1","1","1","1","1","1","1","1","1","1","1","1","1","1","1","1","1","1","1","1","1","1","1","1","1","1","1","1","1","1","1","1","1","1","1","1","1","1","1","1","1","1","1","1","1","1","1","1","1","1","1","1","1","1","1","1","1")
But I think this is an array. So, it can do that and i tried this
val a = Array[String]("1","2","3");echo(a)
This code must be wrong, so here's my first question, why is this happening?
and, if i try to write this
echo(a : _*)
It's right,the second question is, what does this sign means '_*'? I can't use this code in other ways like in for(). So, is echo(a : _ *) is a right code?
The echo function is defined to take a variable number of string arguments. This is really only syntactic sugar; the compiler will insert the necessary instructions to wrap the arguments in an array and then pass the array. So the function will actually only receive a single argument at runtime.
The reason you can't pass the array directly is that there is no additional compiler logic to automagically figure out that the string arguments are already wrapped. The function declaration indicates that zero or more strings are expected, the parameter is actually an array, and a compiler error results.
The : _* notation is additional syntactic sugar to account for this problem; by using this syntax you indicate to the compiler that you are intentionally passing an array instead of the variable number of string parameters.
Take:
var data = List[(DateTime, Double)]()
val pairs = io.Source.fromInputStream(getClass.getResourceAsStream("/data.csv")).getLines().map(_.split(","))
pairs.foreach(pair => data ::= (dateFormatter.parseDateTime(pair(0)), pair(1).toDouble))
No issues with that. If we decide to make use of the parameter placeholder instead of declaring pair, like so:
pairs.foreach(data ::= (dateFormatter.parseDateTime(_(0)), _(1).toDouble))
the compiler will not take it. Furthermore, the error:
too many arguments for method ::: (x: B)List[B]
pairs.foreach(data ::= (dateFormatter.parseDateTime(_(0)), _(1).toDouble))
^
is not too helpful. What is going on here? I understand that the underscore cannot be used to represent more than one parameter, but it's only being used here as a stand-in for one parameter. I do not understand why the compiler will not take this, nor do I understand its reference to method :::, which is not being invoked.
Underscores in a closure refer to the closure's parameters in declaration order, and cannot be used to refer to the same parameter.
Regarding the compiler error, it refers to the method ::, not ::: - the third colon is part of the error message, not of the method name! It is being invoked because of the assignment operator ::=.
The parameter placeholder _ can be used at most one time for each parameter.
So the first time it appears it maps to the first parameter, and the second time it appears it maps to the second parameter, and so forth. If there are more '_' than parameters, that's going to be a compilation problem.
I've been working on learning the ins and outs of scala, and recently I've come across something I'm curious about.
As I understand, if I want to pass a block of code that is effectively lazily evaluated to a function, (without evaluating it on the spot) I could type:
def run(a: =>Int):Int = {...}
In this sense, the function run receives a block of code, that is yet to be evaluated, which it evaluates and returns the computed Int of. I then tried to extend this idea to the List data structure. Typing:
def run(a: List[=>Int]) = {...}
This however, returns an error. I was wondering why this is disallowed. How, other than by this syntax can I pass a list of unevaluated blocks of code?
=>Int is the syntax for by name parameters. =>Int is not a type, so it can't be used as a parameter to List. However, ()=>Int is a type. It's the type of nullary functions that return Int. So this works:
def run(a: List[()=>Int]) = {...}
by-name parameter is not a first-class type in Scala.
List[()=>Int] is one of the solution. otherwise, You can use following Lazy data structure.
https://gist.github.com/1164885
https://github.com/scalaz/scalaz/blob/v6.0.4/core/src/main/scala/scalaz/Name.scala#L99-107
https://github.com/scalaz/scalaz/blob/v7.0.0-M7/core/src/main/scala/scalaz/Name.scala#L37-L60
https://github.com/scala/scala/blob/v2.10.0/src/reflect/scala/reflect/internal/transform/Transforms.scala#L9-23
https://github.com/harrah/xsbt/blob/v0.12.1/compile/api/SafeLazy.scala
https://github.com/okomok/ken/blob/0.1.0/src/main/scala/com/github/okomok/ken/Lazy.scala
https://github.com/playframework/Play20/blob/2.1-RC1/framework/src/play/src/main/scala/play/api/libs/functional/Util.scala#L3-L11