Is it possible to modify the precedence of any self-defined operators?
For example, I implement elementary arithmetic with totally self-defined operators.
case class Memory(name:String){
var num:Num = null
def <<=(x:Num): Unit = {
println(s"assign ${x.value}")
this.num = x
}
}
case class Num(var value:Int) {
def +|+(x:Num) = {
println("%d + %d = %d".format( value,x.value,x.value + value ))
Num(value + x.value)
}
def *|*(x:Num) = {
println("%d * %d = %d".format( value,x.value,x.value * value ))
Num(value * x.value)
}
}
val m1 = Memory("R")
val a = Num(1)
val b = Num(3)
val c = Num(9)
val d = Num(12)
m1 <<= a *|* b +|+ c +|+ d *|* a
println("final m1 ",m1.num.value)
The results are
1 * 3 = 3
3 + 9 = 12
12 * 1 = 12
12 + 12 = 24
assign 24
(final m1 ,24)
Apparently the precedence is correct. I want *|* be the same precedence as * and +|+ the same as +, <<= is equivalent as = as well. How scala figure it out?
Answering the question about modyfing operator precedence - to change it you basically just have to change the first character of your custom operator - this is how scala figures out precedense for infix operators, by just looking at the first character. So if you eg. add an operator *|+:
It will have same precedence as *|*, like with * and *.
"Bigger" precedence than +|+, just like with * and +.
Unfortunately there is no other way to deal with it right now. No custom annotations/weights and so on to avoid making reading code too fuzzy.
The precedence rules are very well summarized here - Operator precedence in Scala.
About your issue though - you get the right results.
*|*, as well as * are left-associative operators and their first character is *, so they have equal precedense.
Your operation:
a *|* b +|+ c +|+ d *|* a
Translates to
a * b + c + d * a, which is 1 * 3 + 9 + 12 * 1.
Applying standard precedence rules - (a*b) + c + (d*a) result is 24.
Related
I'm trying to write a code in Scala to calculate the sum of elements from x to y using a while loop.
I initialize x and y to for instance :
val x = 1
val y = 10
then I write a while loop to increment x :
while (x<y) x = x + 1
But println(x) gives the result 10 so I'm assuming the code basically does 1 + 1 + ... + 1 10 times, but that's not what I want.
One option would be to find the sum via a range, converted to a list:
val x = 1
val y = 10
val sum = (x to y).toList.sum
println("sum = " + sum)
Output:
sum = 55
Demo here:
Rextester
Here's how you would do it using a (yak!) while loop with vars:
var x = 1 // Note that is a "var" not a "val"
val y = 10
var sum = 0 // Must be a "var"
while(x <= y) { // Note less than or equal to
sum += x
x += 1
}
println(s"Sum is $sum") // Sum = 55 (= 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10)
Here's another, more functional, approach using a recursive function. Note the complete lack of var types.
val y = 10
#scala.annotation.tailrec // Signifies add must be tail recursive
def add(x: Int, sum: Int): Int = {
// If x exceeds y, then return the current sum value.
if(x > y) sum
// Otherwise, perform another iteration adding 1 to x and x to sum.
else add(x + 1, sum + x)
}
// Start things off and get the result (55).
val result = add(1, 0)
println(s"Sum is $result") // Sum is 55
Here's a common functional approach that can be used with collections. Firstly, (x to y) becomes a Range of values between 1 and 10 inclusive. We then use the foldLeft higher-order function to sum the members:
val x = 1
val y = 10
val result = (x to y).foldLeft(0)(_ + _)
println(s"Sum is $result") // Sum is 55
The (0) is the initial sum value, and the (_ + _) adds the current sum to the current value. (This is Scala shorthand for ((sum: Int, i: Int) => sum + i)).
Finally, here's a simplified version of the elegant functional version that #TimBiegeleisen posted above. However, since a Range already implements a .sum member, there is no need to convert to a List first:
val x = 1
val y = 10
val result = (x to y).sum
println(s"Sum is $result") // Sum is 55
(sum can be thought of as being equivalent to the foldLeft example above, and is typically implemented in similar fashion.)
BTW, if you just want to sum values from 1 to 10, the following code does this very succinctly:
(1 to 10).sum
Although you can use Scala to write imperative code (which uses vars, while loops, etc. and which inherently leads to shared mutable state), I strongly recommend that you consider functional alternatives. Functional programming avoids the side-effects and complexities of shared mutable state and often results in simpler, more elegant code. Note that all but the first examples are all functional.
var x = 1
var y = 10
var temp = 0
while (x < y) {
temp = temp+x
x = x + 1
}
println(temp)
This gives required result
I am trying to understand aggregate in Scala and with one example, i understood the logic, but the result of second one i tried confused me.
Please let me know, where i went wrong.
Code:
val list1 = List("This", "is", "an", "example");
val b = list1.aggregate(1)(_ * _.length(), _ * _)
1 * "This".length = 4
1 * "is".length = 2
1 * "an".length = 2
1 * "example".length = 7
4 * 2 = 8 , 2 * 7 = 14
8 * 14 = 112
the output also came as 112.
but for the below,
val c = list1.aggregate(1)(_ * _.length(), _ + _)
I Thought it will be like this.
4, 2, 2, 7
4 + 2 = 6
2 + 7 = 9
6 + 9 = 15,
but the output still came as 112.
It is ideally doing whatever the operation i mentioned at seqop, here _ * _.length
Could you please explain or correct me where i went wrong.?
aggregate should be used to compute only associative and commutative operations. Let's look at the signature of the function :
def aggregate[B](z: ⇒ B)(seqop: (B, A) ⇒ B, combop: (B, B) ⇒ B): B
B can be seen as an accumulator (and will be your output). You give an initial output value, then the first function is how to add a value A to this accumulator and the second is how to merge 2 accumulators. Scala "chooses" a way to aggregate your collection but if your aggregation is not associative and commutative the output is not deterministic because the order matter. Look at this example :
val l = List(1, 2, 3, 4)
l.aggregate(0)(_ + _, _ * _)
If we create one accumulator and then aggregate all the values we get 1 + 2 + 3 + 4 = 10 but if we decide to parallelize the process by splitting the list in halves we could have (1 + 2) * (3 + 4) = 21.
So now what happens in reality is that for List aggregate is the same as foldLeft which explains why changing your second function didn't change the output. But where aggregate can be useful is in Spark for example or other distributed environments where it may be useful to do the folding on each partition independently and then combine the results with the second function.
I am having difficulty understanding why this code does not work. I have a polynomial 1 + 3x + 2x^2, which I represent as a list (1.0, 3.0, 2.0). To avoid powering up numbers with decimals to high indexes, I evaluate the polynomial as follows:
1 + x(3 + x(2))
For higher polynomials it would be a0 + x (a1 + x (a2 + x (a3 + ...)))...)
This can be conveniently evaluated right to left, and while I can easily write a loop, I thought Scala's fold operator might be useful. So I tried this on the Scala prompt but got the wrong answer (it should be 28.0)
scala> List(1.0, 3.0, 2.0).tail.foldRight(0.0)((a,x) => 3.0 * a + x)
res53: Double = 15.0
Here is how I expect the calculation on the fold to go:
3 * 0 + 2 = 2
3 * 2 + 3 = 9
3 * 9 + 1 = 28
Have I misunderstood the fold operator, or is there something trivial I missed? Thanks!
Edit; got it:
scala> List(1.0, 3.0, 2.0).foldRight(0.0)((a,x) => 3.0 * x + a)
res68: Double = 28.0
Using tail doesn't fold it as you describe in the steps above since it skips 1.0. Also, swap the arguments x and a.
scala> List(1.0, 3.0, 2.0).foldRight(0.0)((x,a) => 3.0 * a + x)
res34: Double = 28.0
F# Computation Expressions allow to hide the complexity of monadic syntax behind a thick layer of syntactic sugar. Is there something similar available in Scala?
I think it's for comprehensions ...
Example:
val f = for {
a <- Future(10 / 2) // 10 / 2 = 5
b <- Future(a + 1) // 5 + 1 = 6
c <- Future(a - 1) // 5 - 1 = 4
} yield b * c // 6 * 4 = 24
val result = f.get
But it doesn't really feel right. Is there a better syntax?
for exemple in haskell you would have
main = do fromHandle <- getAndOpenFile "Copy from: " ReadMode
toHandle <- getAndOpenFile "Copy to: " WriteMode
contents <- hGetContents fromHandle
hPutStr toHandle contents
hClose toHandle
putStr "Done."
this unlike scala doesn't look like a foreach loops.
Scala syntax seem to have too strong coupling with List comprehension which is a distinct concept. Which prevent me from writing internal DSL (monad) that doesn't look strange.
The missing piece is probably the use of = is scala's for-comprehensions:
val f = for {
a <- Future(10 / 2) // 10 / 2 = 5
b <- Future(a + 1) // 5 + 1 = 6
c <- Future(a - 1) // 5 - 1 = 4
d = b * c // 6 * 4 = 24
} yield d
val result = f.get
With judicious mixing of both <- and =, you should have all the flexibility you need.
It seem like there is no such syntax available in scala and we would need to implement it ourself using the compiler plugin architecture.
Here is some imperative code:
var sum = 0
val spacing = 6
var x = spacing
for(i <- 1 to 10) {
sum += x * x
x += spacing
}
Here are two of my attempts to "functionalize" the above code:
// Attempt 1
(1 to 10).foldLeft((0, 6)) {
case((sum, x), _) => (sum + x * x, x + spacing)
}
// Attempt 2
Stream.iterate ((0, 6)) { case (sum, x) => (sum + x * x, x + spacing) }.take(11).last
I think there might be a cleaner and better functional way to do this. What would be that?
PS: Please note that the above is just an example code intended to illustrate the problem; it is not from the real application code.
Replacing 10 by N, you have spacing * spacing * N * (N + 1) * (2 * N + 1) / 6
This is by noting that you're summing (spacing * i)^2 for the range 1..N. This sum factorizes as spacing^2 * (1^2 + 2^2 + ... + N^2), and the latter sum is well-known to be N * (N + 1) * (2 * N + 1) / 6 (see Square Pyramidal Number)
I actually like idea of lazy sequences in this case. You can split your algorithm in 2 logical steps.
At first you want to work on all natural numbers (ok.. not all, but up to max int), so you define them like this:
val naturals = 0 to Int.MaxValue
Then you need to define knowledge about how numbers, that you want to sum, can be calculated:
val myDoubles = (naturals by 6 tail).view map (x => x * x)
And putting this all together:
val naturals = 0 to Int.MaxValue
val myDoubles = (naturals by 6 tail).view map (x => x * x)
val mySum = myDoubles take 10 sum
I think it's the way mathematician will approach this problem. And because all collections are lazily evaluated - you will not get out of memory.
Edit
If you want to develop idea of mathematical notation further, you can actually define this implicit conversion:
implicit def math[T, R](f: T => R) = new {
def ∀(range: Traversable[T]) = range.view map f
}
and then define myDoubles like this:
val myDoubles = ((x: Int) => x * x) ∀ (naturals by 6 tail)
My personal favourite would have to be:
val x = (6 to 60 by 6) map {x => x*x} sum
Or given spacing as an input variable:
val x = (spacing to 10*spacing by spacing) map {x => x*x} sum
or
val x = (1 to 10) map (spacing*) map {x => x*x} sum
There are two different directions to go. If you want to express yourself, assuming that you can't use the built-in range function (because you actually want something more complicated):
Iterator.iterate(spacing)(x => x+spacing).take(10).map(x => x*x).foldLeft(0)(_ + _)
This is a very general pattern: specify what you start with and how to get the next given the previous; then take the number of items you need; then transform them somehow; then combine them into a single answer. There are shortcuts for almost all of these in simple cases (e.g. the last fold is sum) but this is a way to do it generally.
But I also wonder--what is wrong with the mutable imperative approach for maximal speed? It's really quite clear, and Scala lets you mix the two styles on purpose:
var x = spacing
val last = spacing*10
val sum = 0
while (x <= last) {
sum += x*x
x += spacing
}
(Note that the for is slower than while since the Scala compiler transforms for loops to a construct of maximum generality, not maximum speed.)
Here's a straightforward translation of the loop you wrote to a tail-recursive function, in an SML-like syntax.
val spacing = 6
fun loop (sum: int, x: int, i: int): int =
if i > 0 then loop (sum+x*x, x+spacing, i-1)
else sum
val sum = loop (0, spacing, 10)
Is this what you were looking for? (What do you mean by a "cleaner" and "better" way?)
What about this?
def toSquare(i: Int) = i * i
val spacing = 6
val spaceMultiples = (1 to 10) map (spacing *)
val squares = spaceMultiples map toSquare
println(squares.sum)
You have to split your code in small parts. This can improve readability a lot.
Here is a one-liner:
(0 to 10).reduceLeft((u,v)=>u + spacing*spacing*v*v)
Note that you need to start with 0 in order to get the correct result (else the first value 6 would be added only, but not squared).
Another option is to generate the squares first:
(1 to 2*10 by 2).scanLeft(0)(_+_).sum*spacing*spacing