http://seancorfield.github.io for newer blog posts." />

An Architect's View

CFML, Clojure, Software Design, Frameworks and more...

An Architect's View

Seven Languages: Io, Day 2

December 16, 2010 · 8 Comments

Unlike Ben Nadel, I don't intend to post my homework from each day of this exploration but I said in a comment on Ben's blog that I'd post some of my solutions. Today, I'm posting part of my Io Day 2 homework.

fibhelper := method( a, b, c,
   if( c <= 1,
      a,
      fibhelper( b, a+b, c-1 )
   )
)
fib := method( n,
   fibhelper( 1, 1, n )
)
for(i,1,10,
   writeln( "fib(", i, ")=", fib( i ) )
)

It's weird. This was one of the standard examples everyone always wrote in every new language they learned, back in the day. Yet faced with it yesterday, I drew a complete blank. I wanted to create an infinite lazy sequence of fibonacci numbers and then just walk to the Nth number. It actually took me a while to come up with the code above - and that was after several attempts at a straightforward loop. The recursive version is just the natural way I think, I guess!

I'll try to convert the recursive version into a loop and post that.

OK, now I have the recursive version, here's my iterative version:

fibr := method( n,
   f1 := 1
   f2 := 1
   for( i, 1, n-1,
      f := f1 + f2; f1 := f2; f2 = f
   )
   f1
)
for(i,1,10,
   writeln( "fib(", i, ")=", fibr( i ) )
)

Meanwhile, here's Ben Nadel's version of the Io Day 2 homework.

Tags: programming

8 responses so far ↓

  • 1 Ben Nadel // Dec 17, 2010 at 7:43 AM

    I'm actually starting to get used to the idea of having no explicit return statement. As I was working on Scala, it actually became kind of a game to get the last statement in a function to return the correct data type and do a whole bunch of work!

    Of course, it's so new to me that I cannot necessarily judge "readability" vs funness of writing.
  • 2 Sean Corfield // Dec 17, 2010 at 8:47 AM

    @Ben, think of everything as an expression instead of a statement!

    Consider that you can do this in Scala (and something similar in Io):

    val x = { val y = 42; y / 7 }

    That block has a value and so it's an expression - yet you can declare new variables etc inside that expression.

    This only seems odd because you've worked with languages before that _prohibit_ this kind of thing.

    It's like x = y - in some languages that is a statement with no returned value but in other languages it's an expression and returns the assigned value:

    a = 2 + ( b = 11 ) // assigns 11 to b and 13 to a
  • 3 Ben Nadel // Dec 17, 2010 at 8:56 AM

    I've seen a taste of this in other languages. Even ColdFusion *occasionally* lets you do this. From what I remember off the top of my head, it works in the Conditional loop:

    <cfloop condition="(value = do.something())">

    This will set Value and test for its truthiness. But, I think that might be the only place in ColdFusiong where it lets you do that.

    This kind of thing has been useful in Javascript.

    Going back to your example, though, is the stuff in between your { } a closure? I get so confused between code blocks and closures and functions (oh my!). Is that like doing this (in JS):

    var x = (function(){ var y = 42; return( y / 7 ); })();

    I love the syntactic sugar that these languages are using; but, at times, I find it makes it difficult to understand what is actually going on.
  • 4 Sean Corfield // Dec 17, 2010 at 11:08 AM

    "Going back to your example, though, is the stuff in between your { } a closure?"

    Not in this case: it's just a code block that is executed to obtain a value (that is then assigned to x).

    You can compare the following in the REPL:

    val x1 = { println("Bang!"); val y = 42; y / 7 }

    lazy val x2 = { println("Bang!"); val y = 42; y / 7 }

    In the first case, Bang! is printed and then x1 : Int = 6 showing the code block was evaluated and the result assigned as part of the declaration.

    In the second case, x2 has a lazy value - a closure effectively - and it is not executed until you use the value of x2, at which point it will print Bang! and return the value. Subsequent uses of x2 just return the (previously computed) value.

    Finally, look at:

    def x3 = { println("Bang!"); val y = 42; y / 7 }

    The type displayed in the REPL is x3: Int and x3 behaves just like a value - except the code block is executed _every time_ you use x3.
  • 5 Ben Nadel // Dec 17, 2010 at 12:06 PM

    I hadn't seen Lazy before, very interesting. It's like some just-in-time execution.

    The fact that x3 is treated like a value, is this because functions in Scala can be invoked without parenthesis (assuming they have no arguments)? so, "x3" is kind of like "x3()"... although I think Scala will actually not let you use the parenthesis... I think.

    I'm happy it's Friday, my brain is exhausted.
  • 6 Sean Corfield // Dec 17, 2010 at 4:14 PM

    @Ben, well the type of x3 is Int so for all intents and purposes, it is a pure value (and, no, you can't say x3() to call it).

    OTOH:

    def x4() = { println("Bang!"); val y = 42; y / 7 }

    The type of x4 is displayed as ()Int - a function of no arguments returning Int - when you define it and now you can call x4() (and, of course, you can also call it with plain old x4 without parentheses).
  • 7 Ben Nadel // Dec 18, 2010 at 10:23 AM

    It's interesting to see how hard some of these languages are leveraging subtle syntax variations. I definitely don't see that in my other languages (as much).
  • 8 Florian Kammermann // Mar 19, 2012 at 3:54 PM

    The recursion with one method

    fib := method(
    index, end, end_minus_one, pos,
    if(index <= 2, return 1)
    if(end == nil, end := 1; end_minus_one := 1; pos := 2)
    if(index == pos, return end_minus_one + end)
    fib(index, end_minus_one + end, end, pos + 1)
    )
    for(i,1,10,
    writeln( "fib(", i, ")=", fib( i ) )
    )

Leave a Comment

Leave this field empty