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.
Related
I'm relatively new to Scala so I'm not super confident with the language and I need your help to solve a problem. I know that the for-comprehension is just a syntactic sugar to simplify complex map/flatMap hierarchies.
Now, consider to have 3 different Range intervals, which should be combined in order to create all the possible combinations (respecting the intervals) of values.
Example:
Using the for-comprehension the problem can be solved as:
val intervalX = 1 to 5
val intervalY = 6 to 13
val intervalZ = 20 to 50
for {
x <- intervalX;
y <- intervalY;
z <- intervalZ
} yield (x,y,z)
Which is converted by the Scala compiler as:
intervalX.flatMap{x =>
intervalY.flatMap{y =>
intervalZ.map{z => (x,y,z)}
}
}
However, the problem is harder if you are given in input a variable number d of intervals. Is it possible to perform the same operation, obtaining all the possible d-tuples? I think that it could be solved using the foldLeft operation, but I am not able to write it correctly at the moment. Can you help me?
Thanks
If you can live without tuples as a result then a version using foldLeft and returning lists representing combinations could be:
val intervalX = 1 to 5
val intervalY = 6 to 13
val intervalZ = 20 to 50
val ranges = intervalZ :: intervalY :: intervalX :: Nil
val combos = ranges.foldLeft(Iterable[Seq[Int]](Nil)) { case (c, e) =>
for {
i <- e
j <- c
} yield i +: j
}
combos foreach { println(_) }
I'm new to Scala, and I'm trying to convert this for loop from Java:
for(int x=1, y=2; x<=5; x++, y+=2)
System.out.println(x+y);
I'm trying to zip the values in Scala since I can't find a way to have multiple counters which are non-nested:
val a = Seq(1 to 5)
val b = Seq(2 to 10 by 2)
for((x,y) <- a.zip(b))
println(x+y)
But the above code is giving this error:
type mismatch; found: scala.collection.immutable.Range required: String
Does anyone know how to fix this? I would prefer to do with for loop only, not while loop.
Try this, no need to wrap the Range in a Seq:
val a = 1 to 5
val b = 2 to 10 by 2
for(
(x,y) <- a.zip(b)
)
println(x+y)
You might try . . .
((1 to 5) zip (2 to 10 by 2)).foreach(x => println(x._1+x._2))
Because Scala for comprehensions are sufficiently different from for() loops in other languages, it's often a good idea for beginners to avoid them until they've gained a sufficient knowledge of map, flatMap, and foreach.
In your example you want x to range from 1 to 5 and y is always 2*x. Using for loops is easy for those coming from Java:
for(x <- 1 to 5; y = x*2) {
println(s"x = $x, y = $y, x+y = ${x+y}")
}
Here is solution to a more generic problem - iterating over elements in a collection using multiple counters (=indices or pointers), like if you want to compare each 2 pairs:
val c = List("a", "b", "c", "d") //or any collection
val end = c.length - 1
for(i <- 0 to end-1; j <- i+1 to end)
//compare or operate with each pair
println(c(i)+c(j))
... prints:
ab
ac
ad
bc
bd
cd
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.
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 starting to learn scala. Wonder if anyone has a better way to re-write below code in a more functional way. I know there must be one.
val buf = ((addr>>24)&0xff) + "." + ((addr>>16)&0xff) + "." + ((addr>>8)&0xff) + "." + ((addr)&0xff)
This generates the Range(24, 16, 8, 0) with (24 to 0 by -8) and then applies the function addr >> _ & 0xff to each number using map. Lastly, the mapped Range of numbers is "joined" with . to create a string.
The map is more functional than using the + operator but the rest is just syntactic sugar and a library call to mkString.
val addr = 1024
val buf = (24 to 0 by -8).map(addr >> _ & 0xff).mkString(".")
buf: java.lang.String = 0.0.4.0
val buf = List(24,16,8,0).map(addr >> _).map(_ & 0xff).mkString(".")
Here's how I would do it, similar to Brian's answer but with a short list of values and two simple map() methods using Scala's famous '_' operator. Great question!
Some would find the for comprehension a little bit more readable:
(for (pos <- 24 to 0 by -8) yield addr >> pos & 0xff) mkString "."
The advantage is that input - can be ANY number of integers
// trick
implicit class When[F](fun: F) {
def when(cond: F => Boolean)(tail: F => F) = if (cond(fun)) tail(fun) else fun
}
// actual one-liner
12345678.toHexString.when(1 to 8 contains _.length % 8)
(s => "0" * (8 - s.length % 8) + s ).reverse.grouped(2).map
(Integer.parseInt(_, 16)).toList.reverse.mkString(".")
// 0.203.22.228
// a very big IPv7
BigInt("123456789012345678901").toString(16).when(1 to 8 contains _.length % 8)
(s => "0" * (8 - s.length % 8) + s ).reverse.grouped(2).map
(Integer.parseInt(_, 16)).toList.reverse.mkString(".")
// 0.0.0.96.27.228.249.24.242.99.198.83
EDIT
Explanation because of downvotes. implicit class When can be just a library class, it works in 2.10 and allows conditionally execute some of functions in a calls chain. I did not measure performance, and don't care, because an example itself is meant to be an illustration of what is possible, elegant or not.