I have the following code:
def findNonEqualTuples(value: String): List[(Char, Char)] = {
val result = ListBuffer((Char,Char))
for (current <- 0 until value.length / 2) {
if (!value.charAt(current).equals(value.charAt(value.length - 1 - current))) {
val tuple = (value.charAt(current), value.charAt(value.length - 1 - current))
result += tuple
}
}
return result.toList
}
The line result += tuple says "Type mismatch, expected: (Char.type, Char.type) actual: (Char, Char)". I am quite new to scala. Could someone explain what is the difference between these two types and how I fix it?
Your problem is in how you declare the result ListBuffer. Try:
val result = ListBuffer[(Char,Char)]()
Square-bracket notation is used for specifying parameter types. The compiler's interpretation of your code is that you want to create a new ListBuffer initialised to contain the tuple (Char, Char), that is, a tuple containing the Char type (more accurately, as noted by #LuigiPlinge, it is the Char companion object - paired with itself) - hence the mismatch error.
EDIT - addressing the question in your comment:
this is a different type of braces issue :)
The key is to remember that even operators in Scala are in fact method calls,
so that result += (...) is actually sugar for:
result = result.+(...) // since "op=" is sugar for x = x op ...
ie. calling the += method with the arguments contained within the parentheses. So, to pass a single argument consisting of a tuple, we need an extra set of parentheses:
result += ((value.charAt(current), value.charAt(value.length - 1 - current)))
The outer parentheses delimit the method's parameter list, while the inner parentheses encapsulate the tuple.
Related
I am trying to take from a list of tuples (e.g. List[(String, String)]) some words that have the difference between the number of syllables smaller than 2.
If that is ok, I return them - however, I have some issues: I get Unit found and String expected.
def ecrire():String = {
// Choose deux output: List[(Word, Word)]
// I take every tuple of the list and proceed as the element "b"
for (b <- choose_deux()){
val x = b._1
val y = b._2
val diff = Math.abs(x.syllabes - y.syllabes)
// Check if difference between syllables is smaller than 2
if(diff <= 2)
return x.toString() + "\n" + y.toString()
}
}
}
Now I know that probably I have to do a yield at the bottom, but yield what exactly? The idea is that if the condition shown in the "if" is respected, I write the string made of these two elements.
The error is shown at the for loop: type mismatch; found: Unit; required: String
Could you please help me a bit? I am still new and learning!
Type mismatch error is because your for loop doesn't have else statement and you can't return using if inside a for loop. So for loop is not returning anything so scala compiler assumes the return type to be () i.e. unit() and you have defined the return type as String.
Defining the functions in the following way should solve your issue
def diff(x) = Math.abs(x._1.syllabes - x._2.syllabes)
for (b <- choose_deux() if(diff(b) <= 2)) yield b._1.toString() + "\n" + b._2.toString()
I am always fascinated to see how scala always infers the type correctly . How scala does it?
scala> val num = 5
num: Int = 5
scala> val num = "5"
num: String = 5
I know it might be a very stupid question to ask here but i don't know the answer.
Please enlighten me.
Thanks!
There are several methods for inferencing the type of a variable. Mainly using those called inference rules based in logic theory.
There are plenty of papers explaining the theory behind. Here I put a good example (with Scala ;) )
www2.in.tum.de/hp/file?fid=879
While parsing the code compile can infer that 5 is of type Int and "5" is of String type.
In simple terms any value enclosed in double quotes " will be considered String, value enclosed in single quote ' is considered Char and digits are considered Int (unless specified otherwise).
This is further used to used to infer types for expression results.
Consider this example
val a = 5 // translates to val a:Int = 5
val b = "5" // translates to val b:String = "5"
val x = a+1 // expression 1
val y = b+1 // expression 2
In this example the code type of a is inferred as Int and type of b is inferred as String.
Based on this expression 1 calls function Int.+(x: Int): Int which returns Int, hence type of x is guessed to be Int.
Similarly expression 2 calls function StringOps.+(arg0: Any): String which returns String, hence type of y is guessed to be String.
scala> def sum(a:Int)={a} //I have defined the function with a single parameter
sum: (a: Int)Int
sum{val b=10+20} //passing the parameter as expression block
Getting error
scala> sum{val b=10+20}
<console>:9: error: type mismatch;
found : Unit
required: Int
sum{val b=10+20}
Why is it expecting Unit here?
The error is that {val b = 10 + 20} is of type Unit while sum is expecting an Int.
You can either call sum directly without assigning the variable:
sum(10 + 20)
> 30
Or make the block return an Int, like:
sum{
val b = 10 + 20
b // return b, which is an Int
}
> 30
You do not pass an expression but a block with one declaration. Try:
sum(10+20)
You are experiencing a weird combination of syntax error and type-system convention.
The curly braces mark a block (see e.g. the body of your sum function declaration). Function arguments can be passed in juxtaposition or using parenthesis. That is your syntax error.
The type system convention allows languages with side-effects to gently insert these effects into basically any expression. This happens by treating the composition of statements (i.e. the semicolon) as "evaluate these expression but do nothing with the result, then evaluate the next expression". The nothing as result part is combined with the unit type for statements that do not compute anything.
def sum(a:Int)={a}
What this statement does is create a method that takes one Int-typed parameter and returns it.
sum{val b=10+20}
Here you pass a value to your defined method sum. What you're passing is an expression. Scala will, effectively, 'rewrite' that expression before applying it to sum. If we write the expression being passed (val b=10+20) in the REPL we will see what it gets rewritten to:
scala> val b=10+20
b: Int = 30
But this is only part of the story, because the assignment of a value to a name returns nothing. We can see this by putting brackets around the assignment:
scala> { val b=10+20 }
Note that the REPL displays nothing when this happens.
Because the re-written expression includes this evaluation, you're actually passing a scope to the function, in which b is defined. However, that scope doesn't 'return' an Int to be bound to a. To return the result of the b assignment, you have to do one of two things. Either you have to have a call to the variable be the last call in the expression, or have the last call be the calculation itself, and don't assign that to a variable:
sum{ val b=10+20; b } // Explicitly call the bound variable
sum{ 10 + 20 } // Don't assign the variable
I'm reading Programming in Scala by M. Odersky and now I'm trying to understand the meaning of operators. As far as I can see, any operator in Scala is just a method. Consider the following example:
class OperatorTest(var a : Int) {
def +(ot: OperatorTest): OperatorTest = {
val retVal = OperatorTest(0);
retVal.a = a + ot.a;
println("=")
return retVal;
}
}
object OperatorTest {
def apply(a: Int) = new OperatorTest(a);
}
I this case we have only + operator defined in this class. And if we type something like this:
var ot = OperatorTest(10);
var ot2 = OperatorTest(20);
ot += ot2;
println(ot.a);
then
=+
30
will be the output. So I'd assume that for each class (or type?) in Scala we have += operator defined for it, as a += b iff a = a + b. But since every operator is just a method, where the += operator defined? Maybe there is some class (like Object in Java) containing all the defenitions for such operators and so forth.
I looked at AnyRef in hoping to find, but couldn't.
+= and similar operators are desugared by the compiler in case there is a + defined and no += is defined. (Similarly works for other operators too.) Check the Scala Language Specification (6.12.4):
Assignment operators are treated specially in that they can be
expanded to assignments if no other interpretation is valid.
Let's consider an assignment operator such as += in an infix operation
l += r, where l, r are expressions. This operation can be
re-interpreted as an operation which corresponds to the assignment
l = l + r except that the operation's left-hand-side l is evaluated
only once.
The re-interpretation occurs if the following two conditions are
fulfilled.
The left-hand-side l does not have a member named +=, and also cannot
be converted by an implicit conversion to a value with a member named
+=. The assignment l = l + r is type-correct. In particular this implies that l refers to a variable or object that can be assigned to,
and that is convertible to a value with a member named +.
Being new to Scala (2.9.1), I have a List[Event] and would like to copy it into a Queue[Event], but the following Syntax yields a Queue[List[Event]] instead:
val eventQueue = Queue(events)
For some reason, the following works:
val eventQueue = Queue(events : _*)
But I would like to understand what it does, and why it works? I already looked at the signature of the Queue.apply function:
def apply[A](elems: A*)
And I understand why the first attempt doesn't work, but what's the meaning of the second one? What is :, and _* in this case, and why doesn't the apply function just take an Iterable[A] ?
a: A is type ascription; see What is the purpose of type ascriptions in Scala?
: _* is a special instance of type ascription which tells the compiler to treat a single argument of a sequence type as a variable argument sequence, i.e. varargs.
It is completely valid to create a Queue using Queue.apply that has a single element which is a sequence or iterable, so this is exactly what happens when you give a single Iterable[A].
This is a special notation that tells the compiler to pass each element as its own argument, rather than all of it as a single argument. See here.
It is a type annotation that indicates a sequence argument and is mentioned as an "exception" to the general rule in section 4.6.2 of the language spec, "Repeated Parameters".
It is useful when a function takes a variable number of arguments, e.g. a function such as def sum(args: Int*), which can be invoked as sum(1), sum(1,2) etc. If you have a list such as xs = List(1,2,3), you can't pass xs itself, because it is a List rather than an Int, but you can pass its elements using sum(xs: _*).
For Python folks:
Scala's _* operator is more or less the equivalent of Python's *-operator.
Example
Converting the scala example from the link provided by Luigi Plinge:
def echo(args: String*) =
for (arg <- args) println(arg)
val arr = Array("What's", "up", "doc?")
echo(arr: _*)
to Python would look like:
def echo(*args):
for arg in args:
print "%s" % arg
arr = ["What's", "up", "doc?"]
echo(*arr)
and both give the following output:
What's
up
doc?
The Difference: unpacking positional parameters
While Python's *-operator can also deal with unpacking of positional parameters/parameters for fixed-arity functions:
def multiply (x, y):
return x * y
operands = (2, 4)
multiply(*operands)
8
Doing the same with Scala:
def multiply(x:Int, y:Int) = {
x * y;
}
val operands = (2, 4)
multiply (operands : _*)
will fail:
not enough arguments for method multiply: (x: Int, y: Int)Int.
Unspecified value parameter y.
But it is possible to achieve the same with scala:
def multiply(x:Int, y:Int) = {
x*y;
}
val operands = (2, 4)
multiply _ tupled operands
According to Lorrin Nelson this is how it works:
The first part, f _, is the syntax for a partially applied function in which none of the arguments have been specified. This works as a mechanism to get a hold of the function object. tupled returns a new function which of arity-1 that takes a single arity-n tuple.
Futher reading:
stackoverflow.com - scala tuple unpacking