C-like for loop in Scala
(A.k.a. Chapter 3, Exercise 4, Thinking in Scala, revisited.)
This past weekend, on
the Scala mailing list,
Raoul
was seeking a
"... 'regular' for-loop syntax" for Scala.
At some point, he found my
related Thinking in Scala entry, which starts out
by saying "This exercise is just to show what a Java
for loop is like."
I took a look, and saw that it used the old "def parameter"
syntax which no longer exists in Scala.
So I've rewritten the thing three ways
so I could show a little bit about currying.
Please don't consider this entry to be intended to
encourage the use of this kind of syntax. Mostly it's
a chance to show a little of Scala's flexibility and
explore how one might supply a syntax close to what
C/C++/Java folks are used to.
First, here's a straight port of my older
entry, just to update the syntax of the def parameters:
object c3x4_bonus {
def cFor (init: =>unit)
(p: =>boolean)
(incr: =>unit)
(s: =>unit)
: unit =
{
init; while(p) { s ; incr }
}
// Test showing usage:
def main ( args : Array[String] ) = {
var i: Int = -1;
cFor (i= 1)(i < 100)(i= i+1) {
Console.println( i );
}
}
}
In Haskell, function arguments are always
implicitly curry-able. By contrast, in Scala,
you explicitly make a function curry-able
by giving the separately curry-able sections
in different sets of parentheses.
This version (above) keeps the arguments completely curried,
which leads to the somewhat odd-looking invocation
with three sets of parameters. Using this
fully-curry-able version, I suppose you could
package up a loop in pieces, like:
def cFromOne = cFor(i= 1)
def cFromOneTo100 = cFor(i= 1)(i < 100)
// You could supply a different "incr" if desired:
cFromOneTo100 (i= i+2) { <body> }
So, how about if we only partially curry it?
Here, we do so by allowing the three control expressions
to be specified separately from the block.
object cForU {
def cFor (init: =>unit,
p: =>boolean,
incr: =>unit)
(s: =>unit)
: unit =
{
init; while(p) { s ; incr }
}
// Test showing usage:
def main ( args : Array[String] ) = {
var i: Int = -1;
cFor (i= 1, i < 100, i= i+1) {
Console.println( i );
}
}
}
In usage, this version looks very much like a C for loop,
though you have to use commas instead of semicolons.
You can still name a kind of for loop, and supply
the body later:
def cFrom_12_to_100_by_3 = cFor(i= 12, i < 100, i= i+3)
// Usage:
cFrom_12_to_100_by_3 { <body> }
Finally, how about if we go too far? Make it so none
of the arguments are curry-able:
object cForTU {
def cFor (init: =>unit,
p: =>boolean,
incr: =>unit,
s: =>unit)
: unit =
{
init; while(p) { s ; incr }
}
// Test showing usage:
def main ( args : Array[String] ) = {
var i: Int = -1;
cFor (i= 1, i < 100, i= i+1,
Console.println( i )
)
}
}
Notice that the invocation can no longer put
the body in its own separate brace-enclosed thing.
One minor point: since it's evaluated right
away anyway, the "init" fragment might not need to
have the "=>" on it in any of these forms.
One other issue: none of these functions encapsulate
the index variable -- they all depend on the caller
to pre-define "i". I haven't thought that issue through;
I suspect that any solution to it would involve invocation
syntax that diverges further from Raoul's goal of having
a C-like syntax.
1:26:22 PM