GIGO: words unreadable aloud
Mishrogo Weedapeval
 

 

  Sunday 11 February 2007
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   comment/     



Click here to visit the Radio UserLand website. Click to see the XML version of this web page. © Copyright 2007 Doug Landauer .
Last update: 07/3/1; 22:38:16 .
Click here to send an email to the editor of this weblog.

February 2007
Sun Mon Tue Wed Thu Fri Sat
        1 2 3
4 5 6 7 8 9 10
11 12 13 14 15 16 17
18 19 20 21 22 23 24
25 26 27 28      
Jan   Mar

Previous/Next