Underline _ cannot work for some scenario in following code:
case class Item
(
para: Int
)
val a = List(1, 2)
val b = List(Item(1), Item(2))
a foreach {
perA => println(perA * 2) // Line A: ok
}
a foreach {
println(_) // Line B: ok
}
a foreach {
println(_ * 2) // Line C: not ok
}
b foreach {
perB => println(perB.para) // line D: ok
}
b foreach {
println(_.para) // line E: not ok
}
Could someone explain for me about line C & line E, thanks.
TL;DR: the argument of the lambda can be inserted at an unexpected position. Instead of taking
a foreach { println(_.blah) }
and building
a foreach { x => println(x.blah) }
out of it, the compiler instead builds
a foreach { println( x => x.blah ) }
and then fails to derive the type for the argument x.
A) This is the most explicit way to write down the lambda, the only way to make it clearer would be to add a type:
a foreach { perA => println(perA * 2) }
is the same as
a foreach { (x: Int) => println(x * 2) }
This should obviously work.
B) This works because it's one way to write down the function automatically generated from println. It is equivalent to any of the six variants below:
a foreach { (x: Int) => println(x) }
a foreach { x => println(x) }
a foreach { println(_) }
a foreach { println _ }
a foreach { println }
a foreach println
C) Because of the * 2, this here
a foreach { println(_ * 2) }
can no longer be considered just println(_). Instead, it is interpreted as
a foreach { println( { (x: ??!) => x * 2 } ) }
and since println takes no function-valued arguments, it cannot determine what the type of x is supposed to be, and exits with an error.
D) Is essentially the same as A, it works, I hope it's clear.
E) Is a variation of C, but this time, the type-checker isn't looking for something with method *(i: Int), but instead it's looking for something with a member para.
This here:
b foreach { println(_.para) }
is again interpreted as a foreach with a function which ignores elements of b and returns the constant value of the expression println(_.para),
that is:
b foreach { println( { (x: ??!) => x.para } ) }
Again, the inner expression println( { (x: ??!) => x.para } ) does not make any sense, because println does not expect function-valued arguments (it can handle Any, but it's not enough to derive the type of x).
Related
This Scala code compiles under Scala 2.13
val res = new scala.collection.mutable.StringBuilder
"hello".foreach { c =>
if (true) {
(0 until 10).foreach( res += c )
}
}
If you see the foreach method is missing argument for anonymous function. When it is executed it gives an exception StringIndexOutOfBoundsException for res += c which is puzzling since StringBuilder should always be appendable.
Following code runs fine and there are no exceptions. The only change is adding _ as placeholder for foreach parameter function:
val res = new scala.collection.mutable.StringBuilder()
"hello".foreach { c =>
if (true) {
(0 until 10).foreach( _ => res += c )
}
}
The answer to your question lies in String.apply() or StringBuilder.apply() to be more exact.
You see, foreach expects a function. In more exact words, an expression which evaluates to a function.
So, it will first evaluate the expression to get the function then it will apply that function for 0 until 10
so when you consider the first iteration of outer foreach, you have c = 'h' and following,
(0 until 10).foreach(res += c )
Here, res += c will return res after appending h to it.
So... the evaluated function is res or res.apply with res = "h". Hence, the above is actually,
(0 until 10).foreach("h".apply)
So, res.apply(0) goes well... but res.apply(1) fails with StringIndexOutOfBoundsException.
Please see the signature for
def foreach[U](f: A => U): Unit = {
}
(f: A => U) this is a function, not an expression.
I have a word "hi" written in loop.
implicit class Rep(n: Int) {
def times[A](f: => A) { 1 to n foreach(_ => f) }
}
// use it with
130.times { println("hi") }
How to save output?
There are some bugs in your code, here is a correct one:
implicit class Rep(n: Int) {
def times[A](f: => A): Seq[A] = { 1 to n map(_ => f) }
}
// use it with
val myHis = 130.times { "hi" } // returns Vector(hi, hi, hi, hi, hi, ...)
add = otherwise the functions return type is Unit- always add the return type explicit in such cases (: Seq[A]) and the compiler would have helped you.
use map instead of foreach as foreach returns again Unit
println("hi") returns again Unit. The last statement is returned, so it must be the value you want.
To write a file of this:
new java.io.PrintWriter("filename") { write(myHis.mkString(", ")); close }
Be aware this simple example does not handle exception properly - but I think myHis.mkString(", ") is what you are looking for.
Suppose l = List(1, 2, 3):
scala> l foreach { println _ }
1
2
3
scala> l foreach { println }
1
2
3
l foreach { println _ } <=> l foreach { println } because _ can be omitted. But why does the following also produces the same result?
scala> l foreach { println(_) }
1
2
3
Shouldn't the _ be bounded to println instead of foreach?
in other words:
l foreach { println(_) } <=> l foreach { println(x => x) }
and therefore throws an error on missing parameter type?
l foreach { println(_.toString) } produces the expected missing parameter type error
foreach takes a function A => Unit, in this case, Int => Unit
println satisfies this condition, but it is a method, not a function. Scala can get around this though, through a technique called eta expansion. It creates a function that takes the inputs for the method and called the method with those inputs. In your case, it looks similar to (x: Int) => println(x).
Each way you've written accomplishes this.
l foreach { println }
Here Scala is able to infer that you want to treat println as a function and pass it to foreach
l foreach { println _ }
By adding the underscore you explicitly saying that you want to turn the method into a function
l foreach { println(_) }
This is similar to the last, for any method you call, you can use an underscore instead of passing a parameter. By doing this, instead of calling the method you create a partially-applied function. You then pass this function to foreach
l foreach { println(_.toString) }
This is quite a bit different. _.toString creates a function A => String but Scala cannot figure out the correct type for A. Another problem is not you are passing a value to println, so you are calling println and passing the result to foreach instead of turning it into a function. println returns Unit which is the wrong type to pass to foreach
Shouldn't the _ be bounded to println instead of foreach? in other words:
l foreach { println(_) } <=> l foreach { println(x => x) }
No, this is specifically excluded by rules for placeholders in anonymous functions:
An expression e of syntactic category Expr binds an underscore section u, if the following two conditions hold: (1) e properly contains u, and (2) there is no other expression of syntactic category Expr which is properly contained in e and which itself properly contains u.
"Properly contains" means _ never binds itself, and so it never expands to x => x. In your last example, _.toString does properly contain _ and so satisfies both conditions above.
You're forgetting that println(x) can also be written as println x in Scala. If there's only a single argument, the parenthesis are optional.
I am wondering if there is a way to create a temp variable in the parameter list of a custom control structure.
Essentially, I would like create a control structure that looks something like the
for loop where I can create a variable, i, and have access to i in the loop body only:
for(i<- 1 to 100) {
//loop body can access i here
}
//i is not visible outside
I would like to do something similar in my code. For example,
customControl ( myVar <- "Task1") {
computation(myVar)
}
customControl ( myVar <- "Task2") {
computation(myVar)
}
def customControl (taskId:String) ( body: => Any) = {
Futures.future {
val result = body
result match {
case Some(x) =>
logger.info("Executed successfully")
x
case _ =>
logger.error(taskId + " failed")
None
}
}
}
Right now, I get around the problem by declaring a variable outside of the custom control structure, which doesn't look very elegant.
val myVar = "Task1"
customControl {
computation(myVar)
}
val myVar2 = "Task2"
customControl {
computation(myVar2 )
}
You could do something like this:
import scala.actors.Futures
def custom(t: String)(f: String => Any) = {
Futures.future {
val result = f(t)
result match {
case Some(x) =>
println("Executed successfully")
x
case _ =>
println(t + " failed")
None
}
}
}
And then you can get syntax like this, which isn't exactly what you asked for, but spares you declaring the variable on a separate line:
scala> custom("ss") { myvar => println("in custom " + myvar); myvar + "x" }
res7: scala.actors.Future[Any] = <function0>
in custom ss
ss failed
scala> custom("ss") { myvar => println("in custom " + myvar); Some(myvar + "x") }
in custom ss
Executed successfully
res8: scala.actors.Future[Any] = <function0>
scala>
Note that the built-in for (x <- expr) body is just syntactic sugar for
expr foreach (x => body)
Thus it might be possible to achieve what you want (using the existing for syntax) by defining a custom foreach method.
Also note that there is already a foreach method that applies to strings. You could do something like this:
case class T(t: String) {
def foreach(f: String => Unit): Unit = f(t)
}
Note: You can also change the result type of f above from Unit to Any and it will still work.
Which would enable you to do something like
for (x <- T("test"))
print(x)
This is just a trivial (and useless) example, since now for (x <- T(y)) f(x) just abbreviates (or rather "enlongishes") f(y). But of course by changing the argument of f in the above definition of foreach from String to something else and doing a corresponding translation from the string t to this type, you could achieve more useful effects.
I'm trying to implement a simple web application server as a personal project to improve my Scala, but I've hit upon a problem.
I'd like to be able to set up routes using code like the following:
def routes()
{
get("/wobble")
{
...many lines of code here...
}
get("/wibble")
{
...many lines of code here...
}
post("/wibble")
{
...many lines of code here...
}
post("/wobble")
{
...many lines of code here...
}
}
routes is called by the server when it starts and get and post are functions defined by me like this:
get(url:String)(func:()=>String)=addroute("GET",url,func)
post(url:String(func:()=>String)=addroute("POST",url,func)
addroute(method:String,url:String,f:()=>String)
{
routesmap+=(method->Map[String,()=>String](url,func))
}
Unfortunately, I've had nothing but problems with this. Could anyone tell me the correct way in Scala to add an anonymous function (as passed in as a parameter in the defined routes function above) to a Map (or any other Scala collection for that matter)?
Here is a working example:
scala> var funcs = Map[String,(Int)=>Int]()
funcs: scala.collection.immutable.Map[String,Int => Int] = Map()
scala> funcs += ("time10", i => i * 10 )
scala> funcs += ("add2", i => i + 2 )
scala> funcs("add2")(3)
res3: Int = 5
scala> funcs("time10")(10)
res4: Int = 100
You can also add a declared function:
val minus5 = (i:Int) => i - 5
funcs += ( "minus5", minus5)
Or a method:
def square(i: Int) = i*i
funcs += ("square", square)
In your case, you can have two maps, one for GET and one for POST. It should simplify the design (and at most, you will end with four maps if you include DEL and PUT).
May be, this one ? :
type Fonc = ( (=> String) => Unit)
var routesmap = Map[String,Map[String,()=>String]]()
def addRoute(method:String,url:String,f:()=>String) = {
routesmap+=(method-> (routesmap.getOrElse(method,Map[String,()=>String]()) + (url->f)))
}
def get(url:String):Fonc = (x => addRoute("GET",url,() => x))
def post(url:String):Fonc = (x => addRoute("POST",url,() => x))
def routes()
{
post("/wobble")
{
"toto"
}
get("/wibble")
{
"titi"
}
}
you can try this code :
def addRoute(method:String,url:String,f:()=>String) = {
routesmap+=(method-> (routesmap.getOrElse(method,Map[String,()=>String]()) + (url->f)))
}
def get(url:String,func:()=>String)= addRoute("GET",url,func)
def post(url:String,func:()=>String)= addRoute("POST",url,func)
def routes()
{
get("/wobble",()=>{"toto"})
get("/wibble",()=>{println("test")
"titi"})
}
and execute these commands
scala> routes
scala> routesmap.get("GET").get("/wibble")()