Hi, I have a new proposition for improving for-comprehensions in Scala 3.
Motivation
I want to fix the problem that arises from the use of the following code:
//> using scala 3.3.3
//> using lib "dev.zio::zio:2.1.5"
import zio.*
def loop: Task[Unit] =
for
_ <- Console.print("loop")
_ <- loop
yield ()
@main
def run =
val runtime = Runtime.default
Unsafe.unsafe { implicit unsafe =>
runtime.unsafe.run(loop).getOrThrowFiberFailure()
}
This kind of effect loop is pretty commonly used in Scala FP programs and often ends in yield ()
.
The problem with the desugaring of this for-comprehensions is that it leaks memory because the result of loop
has to be mapped over with _ => ()
, which often does nothing.
Proposed Solution
A possible solution that I want to suggest and possibly add to the betterFors
language extension is to remove these unnecessary map
calls generated from yield ()
when the last binding also has type Unit
.
A possible approach could be to add sticky keys to the map
calls generated from for-comprehensions and add a new phase after. That phase would then check for every such map
call if the argument is equivalent to _ => ()
and the previous binding is also of type Unit
.
A naive PoC: Crude implementation of removing trailing unit-literal maps from for-… · KacperFKorban/dotty@31cbd47 · GitHub
Discussion
These changes can be introduced as either a separate SIP or as an addition to the SIP-62 (betterFors).
Let me know what you think.