I am learning the difference between methods and functions. I am following this link
http://jim-mcbeath.blogspot.co.uk/2009/05/scala-functions-vs-methods.html
The article says if you compile the following code:
class test {
def m1(x:Int) = x+3
val f1 = (x:Int) => x+3
}
We should get two files
1. test.class
2. test$$anonfun$1.class
But I do not get it. Secondly the example says if we execute the following command in REPL, we will get the below
scala> val f1 = (x:Int) => x+3
f1: (Int) => Int = <function>
But I get only this
scala> val f1 = (x:Int) => x+3
f1: Int => Int = $$Lambda$1549/1290654769#6d5254f3
Is it because we are using a different version? Please help.
Scala 2.11 and earlier versions behave as shown in the blog post.
The behavior changed in Scala 2.12. Scala now uses the lambda support that was added to version 8 of the JVM, so it doesn't need to emit the extra .class file. As a result, the .jar files produced by 2.12 are usually a lot smaller.
As a side effect of this, Scala can't override toString anymore, so you see the standard JVM toString output for lambdas.
Related
I am using Scala 2.11.8
I have this code
val i1 = Either[ErrorCode, Person] = getMaybePerson().toRight(ErrorCode.NOTFOUND)
val i2 = Either[ErrorCode, (Int, FiniteDuration)] = getMaybeConfig().toRight(ErrorCode.NOCONFIG)
for {
a <- i1.right
(c, d) <- i2.right
} yield {...}
The IDE (IntelliJ 2017.1) does not show any errors. but when I compile from SBT. it says
Warning:(163, 43) `withFilter' method does not yet exist on scala.util.Either.RightProjection[ErrorCode,(Int, scala.concurrent.duration.FiniteDuration)], using `filter' method instead
(maxReward, checkDuration) <- i2.right
Error:(163, 10) constructor cannot be instantiated to expected type;
found : (T1, T2)
required: scala.util.Either[Nothing,(Int, scala.concurrent.duration.FiniteDuration)]
(maxReward, checkDuration) <- i2.right
This is driving me nuts, because In the REPL. I can easily write this code.
Welcome to Scala 2.11.8 (Java HotSpot(TM) 64-Bit Server VM, Java 1.8.0_121).
Type in expressions for evaluation. Or try :help.
scala> case class Person(name: String, age: Int)
defined class Person
scala> val x = Some(Person("foo", 20))
x: Some[Person] = Some(Person(foo,20))
scala> val y = Some(("foo", 20))
y: Some[(String, Int)] = Some((foo,20))
scala> for {
| a <- x.toRight("wrong").right
| b <- y.toRight("wrong").right
| } yield (a.name, a.age, b._1, b._2)
res0: scala.util.Either[String,(String, Int, String, Int)] = Right((foo,20,foo,20))
scala>
The short answer is that Either does not sit well with for comprehensions (at least in scala <2.11).
So you first have to remember that for comprehensions are syntactic sugar for monadic operations map, flatMap, and withFilter.
In particular, when doing pattern matching on an extracted value (such as the (c, d) <- i2.right in your code), this is replaced by (something equivalent to)
i2.right.withFilter(_.isInstanceOf[Tuple2[A, B]]).map{p =>
val (c, d) = p.asInstanceOf[Tuple2[A, B]]
...
}
Now you may see more clearly what the problem is: first, there is no withFilter method on RightProjection, so it uses filter instead (as the error statement says). Then the filter method outputs an Option[Either[ErrorCode, (Int, FiniteDuration)]], so you cannot pattern match with a tuple against it.
If you can get around the filter problem, you will probably come against the problem with map (I know I did):
If you try using an assignment in for comprehension:
for {
a <- Right("foo").right
b = a + "bar"
} yield a + b
This won't work either, because it is replaced by a map call on an Either... but since Either is not right-biased (or left-), it does not have a map method, so the compiler will be lost (and give you some confusing error message, if you don't think about how the for is desugared).
In general, you should avoid using Either in for comprehension if you want to do some filtering (pattern matching included) or assignements. You might want to consider some equivalent monads in some libs, such as Validation or \/ in catz or scalaz.
NB I said something about scala 2.11, because in scala 2.12, Either becomes right-biased, so some of the afore-mentioned problems disappear, but I haven't tried my hands on it yet.
In Scala 2.12.0, the output is something like $$Lambda when assign a function literal to a value, while in 2.11.8, it will be <functionX>. Why there is such a change ? Does $$Lambda mean a lambda expression here ?
2.12.0:
scala> val doubler = (x: Int) => x * 2
doubler: Int => Int = $$Lambda$1276/486758400#52f8f398
2.11.8:
scala> val doubler = (x: Int) => x * 2
doubler: Int => Int = <function1>
On the Java platform, the Scala 2.12 compiler uses the same encoding for anonymous functions that the Java 8+ compiler uses. So, the difference you are seeing is basically that in the first case, you are seeing the output of the toString() method from a Scala Function1[Int, Int] instance, whereas in the second case, you are seeing the toString() of a Java 8 Lambda.
Note, however, that this is a private internal implementation detail of the Scala-JVM compiler. You should not rely on it. It might be, and probably is different on Scala.js and Scala-native.
As part of my learning, I am trying to write the Scala expression into a scala script but struck with an error.
The scala code I am having it successfully executed in Scala REPL is
def intList = List[1,2,3,4,5]
intList.filter(x => x%2 ==1).map(x => x * x).reduce((x,y) => x+y)
This successfully gets executed and the following is the result I get.
scala> intList.filter(x => x % 2 == 1).map(x => x * x).reduce((x,y) => x + y)
res15: Int = 35
I am trying to make this as a Scala script or class so as to rerun any number of times on demand. I save this in a file named SumOfSquaresOfOdd.scala
import scala.collection.immutable.List
object SumOfSquaresOfOdd extends App
{
def main(args:Array[String]):Unit =
{
var intList = List[Integer](1,2,3,4,5,6,7,8,9,10)
def sum = intList.filter(x => x % 2 ==1).map(x => x * x).reduce((x+y) => x + y)
println sum
}
}
When I compile this using scalac, the following error is printed on the console.
λ scalac SumOfSquaresOfOdd.scala
SumOfSquaresOfOdd.scala:8: error: not a legal formal parameter.
Note: Tuples cannot be directly destructured in method or function parameters.
Either create a single parameter accepting the Tuple1,
or consider a pattern matching anonymous function: `{ case (param1, param1) => ... }
def sum = intList.reduce(x => x % 2 ==1).map(x => x * x).reduce((x+y) => x + y)
^
one error found
How do I use the filter, map, reduce methods in a script? Appreciate your help and support.
UPDATE: Typos updated in the code.
I can answer your question:
How do I use the filter, map, reduce methods in a script?
But I can't fully solve your specific use case because you didn't specify what the script should be doing.
Try this code
object SumOfSquaresOfOdd {
def main(args: Array[String]) : Unit = {
var intList = List(1,2,3,4,5,6,7,8,9,10)
def sum = intList.filter(x => x % 2 ==1).map(x => x * x)
println(sum)
}
}
Then
~/Code/stack-overflow $ scalac SumOfSquaresOfOdd.scala
~/Code/stack-overflow $ scala SumOfSquaresOfOdd
List(1, 9, 25, 49, 81)
You seem to be a little lost. Here are some tips:
Use Int rather than Integer; Int is Scala's integer type. And you don't need to import it.
Don't extend App in this case. Refer to this question Difference between using App trait and main method in scala
Use wrapping parens for println
A literal List(1,2,3) will be type-inferenced to List[Int]; no need to explicitly type it. Check in the Scala REPL.
I think you confused reduce with filter. Compare both in the latest scaladoc: http://www.scala-lang.org/api/current/#scala.collection.immutable.List
Other ways to run scala code: http://joelabrahamsson.com/learning-scala-part-three-executing-scala-code/
Highly recommend you do Functional Programming Principles in Scala if you're serious about learning.
Good luck learning Scala! :)
In Scala what is the correct way to implement something like this that produces the error "forward reference extends over definition of value b"?
object a {
def main(args: Array[String]) {
val b: Map[Int, () => Int] = Map(5 -> { () => b.size })
println(b(5)())
}
}
Making b lazy works but that doesn't seem like the correct solution.
EDIT: The other question (What does "Forward reference extends over definition of value" mean in Scala?) is about a bug in Scala itself that where this error is reported incorrectly (or that is what the accepted answer suggests). This question is about what to do when this error is reported correctly. Also I supplied sample code.
Making b lazy seems like overkill because it changes the run-time behavior, when this is a compile-time problem that I assume could be fixed with a different declaration...
As mentioned in the comments, making b a def works too, which seems closer to the solution since def works for recursive functions, but that seems to be reevaluating it at run-time every time it is accessed.
scala> var a = 5
scala> def b = a
scala> a = 2
scala> b
res0: Int = 2
scala> a = 1
scala> b
res1: Int = 1
(with lazy it can be changed before it is accessed but is stored after that)
Both of these seem like run-time solutions to a compile-time problem, I'm looking for something analogous to letrec in Scala.
When you define a non-lazy val, you cannot refer to that val inside its definition. For that you either have to use a def or a lazy val.
I am new to Scala and I am having trouble with an example from the book Scala in Action.
I am using IntelliJ, but I've also tried it as script (REPL). The scala compiler gives me the same error as IntelliJ. (I am using Scala 2.10, as the book suggest).
Here is my code:
def parseArgs(args: Array[String]): Map[String, List[String]] = {
val command = args.head
val params = parseArgs(args)
val url = args.last
def nameValuePair(paramName: String) = {
def values(commaSeparatedValues: String) = commaSeparatedValues.split(",").toList
// x => x + 2
val index = args.indexOf(_ == paramName)
(paramName, if(index == -1) Nil else values(args(index + 1)))
}
Map(nameValuePair("-d"), nameValuePair("-h"))
}
The message I get is:
C:\scala\projects\scripts\restclientscript.scala:12: error: missing parameter type for expanded function ((x$1) => x$1.$eq$eq(paramName))
val index = args.indexOf(_ == paramName)
^
one error found
This is exactly as it is shown in the book but I can't figure out how to make it work.
Also the method indexOf is actually findIndexOf in the book. But that method does not exist the compiler tells me (and the doc: http://www.scala-lang.org/api/2.10.3/index.html#scala.Array).
Lastly, IntelliJ will not accept the == inside the indexOf() method (highlighted red, but compiles).
Any help would be appreciated! :)
The book may be referring to an older version of Scala. Looking at the doc page you linked it is clear that the method indexOf has the following signature:
indexOf(elem: T): Int
That means that the method doesn't expect a closure but instead a value. You probably want to use indexWhere:
indexWhere(p: (T) ⇒ Boolean): Int
That should work!
One more advice is: never trust IntelliJ Idea errors, always double check them with sbt as Idea uses a different algorithm for checking errors and doesn't rely on the actual compiler.
Array.indexOf takes an instance for which the index should be found in the array.
If you want a version with predicate, there's Array.indexWhere (at least according to Scala 2.11 docs) which takes a predicate function p : (T) => Boolean.
So, you can either do:
args.indexOf(paramName)
or
args.indexWhere(_ == paramName)