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
)