Charlie Harvey

Io — Day Two

Wow. Day two messed with my head. I woke up a bit tired this morning to have a crack at it and got really baffled by how to make a fibonacci sequence. Just drew a total blank. So, I dug out some old c code I had and copied that into io. Which is sort of cheating, but got me going and also helped me feel a bit more comfortable with the language. Like Tate says, feeling comfortable with a new language is often about typing some code. Well, my homework excercises with some commentary looked like this.

1. fib.io

A Fibonacci sequence starts with two 1s. Each subsequent number is the sum of the two numbers that came before: 1, 1, 2, 3, 5, 8, 13, 21, and so on. Write a program to find the nth Fibonacci number. fib(1) is 1, and fib(4) is 3. As a bonus, solve the problem with recursion and with loops.

Like I said, my brain was totally blank at first, so I’ve pretty much rewritten C code. By the end of this I was starting to get the hang of how Io approaches stuff. #!/usr/local/bin/io # Iterative version. Probably faster. fib := method( last_index, # save a tiny bit of work # we already know that fib(1) and fib(2) return 1 if (last_index < 3, return 1 ) first := second := 1 for( unused, 1, last_index-1, running_total := first + second first := second; second = running_total; ) return first ) call_count := 0 # A naive and often seen recursive implementation rfib := method ( n, if(n<2, return n ) return rfib(n-1) + rfib(n-2) ) # this and the next method iwork together and are a bit more efficient new_rfib := method (n, if ( n<1, return 0 ) return new_rfib2(n, 0, 1) ) new_rfib2 := method(n,first,second, if( n<2, return second ) return new_rfib2(n-1, second, first+second) ) "\nIterative version\n------------------" println for(i,1,10, writeln( "Iteration ", i, ": ", fib(i) ) ) "\nRecursive version 1\n------------------" println for(i,1,10, writeln( "Iteration ", i, ": ", rfib(i) ) ) "\nRecursive version 2\n------------------" println for(i,1,10, writeln( "Iteration ", i, ": ", new_rfib(i) ) )

2. override_divide.io

How would you change / to return 0 if the denominator is zero?

This mostly took looking at the docs. I tooke the approach of making a copy of the default / operator and passing the figures on to it unless the denomonator was zero. Other people seem to have taken a similar approach. #!/usr/local/bin/io # store the 'core', original divide operator Number div_method := Number getSlot("/") # Now extend the Number class Number / := method(denom, if (denom == 0, return 0, return self div_method(denom)) ) # tests "expect 2" println (14/7) println "expect 0" println (14/0) println

3. list_sum.io

Write a program to add up all of the numbers in a two-dimensional array.

Fortunately the docs for List are very well written, and I chanced across the sum and flatten methods. So it was pretty trivial to implement something that matched the spec. I note that Ben Nadel took a much more "from scratch approach". I’m lazy though. #!/usr/local/bin/io # you can flatten a list, then sum list_sum := method ( list, list flatten sum ) "Expect 10" println list_sum( list( list(1,2), list(3,4))) println

4. my_average.io

Add a slot called myAverage to a list that computes the average of all the numbers in a list. What happens if there are no numbers in a list? (Bonus: Raise an Io exception if any item in the list is not a number.)

Well, the last problem had already introduced the sum method. And reading the docs, sum throws an exception on NaN. So, being lazy, I reused that. #!/usr/local/bin/io List my_average := method ( return sum / size ) x := list (1,2,3) "Expect 2" println x my_average println x := list ("NaN",1,2,3) "Expect Exception" println x my_average println

5..7

All these questions were related so I was able to tackle them all in one lump of code

5. Write a prototype for a two-dimensional list. The dim(x, y) method should allocate a list of y lists that are x elements long. set(x, y, value) should set a value, and get(x, y) should return that value. 6. Bonus: Write a transpose method so that (new_matrix get(y, x)) == matrix get(x, y) on the original list. 7. Write the matrix to a file, and read a matrix from a file.

This was stretching for me, especially the transpose method. Not that the code is super difficult, its just expressing oneself in an unfamiliar language that feels like swimming in treacle. #!/usr/local/bin/io matrix := List clone; matrix dim := method(x,y, self setSize(x); // make first dimension this big for (i, 0, (x - 1), 1, self atPut(i, (list setSize(y)) ) ) ) matrix get := method (x,y, return self at(x) at(y) ) matrix set := method (x,y,value, self at(x) atPut(y,value) return self ) matrix transpose := method ( my_x := self size my_y := self first size my_matrix := matrix clone dim ( my_y, my_x ) // note x and y swapped for (i, 0, (my_x-1), for(j, 0, (my_y-1), my_matrix set(j,i,self get(i,j)) ) ) # Ooh! you can not nother with 'return', just like perl my_matrix ) matrix save := method ( # Borrowed this cute syntax from http://stackoverflow.com/questions/4533478/how-do-i-deserialize-objects-in-io File with("matrix.dat") open write(self serialized) close ) matrix show := method ( for(i, 0, self size-1, for(j, 0, self first size-1, self get(i,j) print if(j<self first size-1, ", " print ) ) "" println ) ) // Tests m:=matrix clone dim(3,3) "\nExpect 3x3 Matrix of nils" println m println m set(0,0,"O") m set(0,1,"O") m set(0,2,"X") m set(2,2,"X") "Expect X" println m get(2,2) println "Expect formatted-ish matrix" println m show m2 := m transpose "Expect formatted transposed matrix" println m2 show m2 save m := doFile("matrix.dat"); "Expect 3x3 matrix" println m println

8. guesser.io

Write a program that gives you ten tries to guess a random number from 1–100. If you would like, give a hint of “hotter” or “colder” after the first guess.

I felt like I was on the home strait with this question, and started to appreciate Tate's characterization of Io as being kinda like Ferris Bueller. The one place where I got stuck was having an "and" in my conditional. Parantheses to the rescue! #!/usr/local/bin/io to_guess := Random value(1,100) round i := 0 prev_diff := nil in := File standardInput; "\n\nGuess my number (1-100, Q to quit)!" println while(i<10, guess := in readLine("Your guess: ") if(guess=="Q", break) // Quit guess := guess asNumber if(guess isNan, continue) // Try again, not a number difference := (to_guess - guess) abs if( difference == 0, "Congratulations, you win!" println break ) if((prev_diff and prev_diff != difference), if(prev_diff > difference, "Warmer" println, "Colder" println ) ) prev_diff := difference )


Comments

  • Be respectful. You may want to read the comment guidelines before posting.
  • You can use Markdown syntax to format your comments. You can only use level 5 and 6 headings.
  • You can add class="your language" to code blocks to help highlight.js highlight them correctly.

Privacy note: This form will forward your IP address, user agent and referrer to the Akismet, StopForumSpam and Botscout spam filtering services. I don’t log these details. Those services will. I do log everything you type into the form. Full privacy statement.