Skip to content

Instantly share code, notes, and snippets.

@judy2k
Created November 3, 2011 10:35
Show Gist options
  • Save judy2k/1336226 to your computer and use it in GitHub Desktop.
Save judy2k/1336226 to your computer and use it in GitHub Desktop.
IO Exercises
Io Typing
=========
Io> 1 + 1
==> 2
Io> 1 + "one"
Exception: argument 0 to method '+' must be a Number, not a 'Sequence'
---------
message '+' in 'Command Line' on line 1
Io> "one" + 1
Exception: Io Assertion 'operation not valid on non-number encodings'
---------
message '+' in 'Command Line' on line 1
It looks to me like Io is strongly typed (it didn't attempt to coerce my String
into a Number), and dynamically typed. The '+' operator simply refers to a
method on the first operand, which is executed, passing the second operand as
the only parameter. The only reason adding a string to a number doesn't work is
because the '1' object's '+' method doesn't accept a Sequence as its argument,
and thus throws an exception.
Boolean Coercion
================
Io> 0 isTrue
==> true
Io> 1 isTrue
==> true
Io> "" isTrue
==> true
Io> nil isTrue
==> false
I think the code above pretty much speaks for itself. Took me ages to discover
the 'isTrue' method though!
Introspection
=============
Use the slotNames method to get a list of slots.
Assignment Operators
====================
The = operator attempts to assign to an existing slot and raises an exception
if the slot has not been defined. Use this for setting the value of an
attribute defined on an object (or it's prototype).
The := Does the same, but will create the slot if it does not already exist.
Use this for defining 'private' attributes for an object.
The ::= operator creates the slot, a getter and setter for the slot, and then
assigns the provided value. Use this for creating 'public' values. Having
setFoo and getFoo methods are the Io idioms for indicating the public interface
for an object.
Ref: http://www.iolanguage.com/scm/io/docs/reference/index.html#/Core/Core/Object/newSlot
#!/usr/bin/env io
# Calcualate a fibonacci sequence value in IO.
#
# The first index is 0, not 1 as indicated in the book.
# Sequences should always be indexed from zero!
rfib := method(n,
if(n < 2, 1, rfib(n-2) + rfib(n-1))
)
lfib := method(n,
t := 1
a := 1
b := 1
for(i, 1, n-1,
t := a + b
a = b
b = t
)
t
)
# Ensure that we get the same values for both implementations:
12 repeat(n, ((rfib(n) asString) .. ": " .. (lfib(n) asString)) println)
#!/usr/bin/env io
Number oldDiv := Number getSlot("/")
Number / := method(n,
if(n == 0, 0, self oldDiv(n))
)
(6 /2) println
(6 /0) println
#!/usr/bin/env io
# It's easy if you know how:
List deepSum := method(flatten sum)
# This actually took me longer than the line above!:
nestedList := list(
list( 1, 2, 3 ),
list( 10, 20, 30 ),
list( 100, 200, 300 )
);
# Prints 666:
nestedList deepSum println
#!/usr/bin/env io
# I'm avoiding the use of List average as that would pretty much defeat the
# purpose of this exercise!
# I couldn't bring myself to call it myAverage:
List mean := method(
if(select(v, (v type) != "Number") size > 0,
Exception raise("Contains non-numeric value(s)!"))
if(size == 0, 0, sum / size)
)
"Prints '7.5'" println
list(1,2,3,24) mean println
# Raises an Exception:
# list(1,2,3,"24") mean println
# Calculate the Median: Just because I felt like it
# =================================================
# Don't know why I did this - I think I was just mildly annoyed by BT's lack
# of detail:
List median := method(
# Ensure List contents are numeric:
if(select(v, (v type) != "Number") size > 0,
Exception raise("Contains non-numeric value(s)!"))
# Empty list returns zero:
if(size == 0, 0,
middle := size / 2
# Slightly more complicated for even-length lists:
if(size % 2 == 0) then (
# Mean of middle two values:
return((at(middle - 1) + at(middle)) / 2)
) else (
# Middle value:
return(at(middle floor))
)
)
)
"Prints '2.5'" println
list(1,2,3,24) median println
"Prints '3'" println
list(1,2,3,4,24) median println
# Raises an Exception:
# list(1,2,3,"24") median println
#!/usr/bin/env io
TwoDList := Object clone
# Decided to implement this as a factory method:
TwoDList dim := method(x, y,
result := TwoDList clone
result rows := list() preallocateToSize(y)
y repeat(
result rows append(list() setSize(x))
)
return result
)
# Set a cell value:
TwoDList set := method(x, y, value,
rows at(y) atPut(x, value)
return self
)
# Get a cell value:
TwoDList get := method(x, y,
rows at(y) at(x)
)
# Handy print method:
TwoDList print := method(
"(" println
rows foreach(row,
(" " .. row join(", ")) println
)
")" println
return self
)
# Always do the bonus exercise!
TwoDList transpose := method(
TwoDList result := TwoDList dim(rows size, rows at(0) size)
rows size repeat(y,
rows at(y) size repeat(x,
result set(y, x, get(x, y))
)
)
return result
)
# Create a 4 by 5 matrix and print out:
matrix := TwoDList dim(4, 5)
matrix set(0,0, "0-0") set(3,0, "3-0")
matrix set(0,4, "0-4") set(3,4, "3-4")
matrix println
# Transpose the matrix, print, and ensure the requirements are met:
new_matrix := matrix transpose
new_matrix println
4 repeat(x,
5 repeat(y,
if (matrix get(x, y) != new_matrix get(y, x)) then (
a := matrix get(x, y)
b := new_matrix get(y, x)
Exception raise("#{a} and #{b} don't match at (#{x}, #{y}) and (#{y}, #{x})" interpolate)
)
)
)
# Write to a file as a non-escaped CSV:
TwoDList writeToFile := method(path,
out := File openForUpdating(path)
rows foreach(row,
out write(row join(", "))
out write("\n")
)
out close
return self
)
matrix writeToFile("matrix_output.txt")
# Read a matrix from a poor CSV file:
TwoDList readFromFile := method(path,
in := File open(path)
rows = list()
in foreachLine(line,
rows append(line removeSuffix("\n") split(", "))
)
in close
return self
)
# Read in matrix and print to screen:
"Read from file:" println
matrix2 := TwoDList dim(0,0) readFromFile("matrix_output.txt")
matrix2 println
#!/usr/bin/env io
num := (Random value(99) floor + 1) println
stdin := File standardInput
10 repeat(i,
guess_num := i + 1
guess := (stdin readLine( "Guess #{guess_num} of 10: " interpolate) asNumber)
if (guess == num) then (
"Well done! You guessed it!" println
break
) else (
if(i == 9) then (
"Sorry, you ran out of guesses!" println
) elseif (guess < num) then (
"Bigger" println
) else (
"Smaller" println
)
)
)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment