Io, Day 3

Final day with Io. It’s been quite a ride, and even if I don’t think I grasp everything that Io is, I consider playing with Io a little bit on my own later because of it’s potential, especially in DSL.

Enhance the XML program to add spaces to show the indentation structure
Builder := Object clone
Builder depth := 0
 
Builder forward := method(
  prefix := "  " repeated(self depth)
  writeln(prefix, "<", call message name, ">")
  self depth = self depth + 1
  call message arguments foreach(arg,
    content := self doMessage(arg)
    if(content type == "Sequence", writeln(prefix, "  ", content))
  )
  self depth := self depth - 1
  writeln(prefix, "</", call message name, ">")
)
 
Builder html(head(title("Programing languages")), body(ul(li("IO"), li("Lua"), li("JavaScript"))))
Create a list syntax that uses brackets
curlyBrackets := method(
  l := List clone
  call message arguments foreach(arg,
    l append(doMessage(arg))
  )
  return l
)

Io, Day 3

Let’s get down to some coding.

Write a method to find the nth Fibonacci number, both iteratively and recursively
Fibonacci := Object clone
 
Fibonacci iter := method(n, 
  l := list(1, 1)
  for(i, 2, n, 1, 
    l append(l at(i - 2) + l at(i - 1))
  )
  l at(n - 1)
)
 
Fibonacci rec := method(n,
  if(n &lt; 3, 1, 
    rec(n - 1) + rec(n - 2)
  )
)
 
x := Fibonacci iter(12)
x println
 
y := Fibonacci rec(12)
y println
How would you change the operator / to return 0 is the denominator is zero

For this one, I was a bit stuck with only the book and the language reference, so I had to Google it. And that’s where you have all the beauty and annoyance of the internet: one of the first hit is a solution to that exact question on StackOverflow (it was to be expected.) I was expecting this exercise to take me to the OperatorTable for which there is an example in the book, but actually the operator already exists so it does not have to be added, but instead re-defined for the Number type.

Write a program to add up all the numbers in a two-dimensional array
a := list(list(1, 2, 3))
a append(list(4, 5, 6, 7, 8, 9))
a append(list(10, 11, 12))
a append(list(13, 14, 15, 16, 17, 18, 19, 20))
 
total := 0
 
for(i, 0, a size - 1,
  b := a at(i)
  for(j, 0, b size - 1,
    n := b at(j)
    total = (total + n)
  )
)
 
total println
Add an myAverage slot 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 exception if any item in the list is not a Number.
a := list(1, 2, 3, 4, 5)
b := list(1, "hello")
 
List myAverage := method(
  total := 0
  for(i, 0, self size -1,
    n := self at(i)
    if (n type != "Number",
      Exception raise("An item in the list is not a Number"),
      total = total + n
    )
  )
  total / self size
)
 
a myAverage println
b myAverage println
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. The set(x, y, value) method should set a value and the get(x, y) method should return that value.
Matrix := Object clone
 
Matrix list := nil
 
Matrix dim := method(x, y,
  self list := List clone
  for(i, 0, x - 1,
    l := List clone
    for(j, 0, y - 1, l append(nil))
    self list append(l)
  )
)
 
Matrix set := method(x, y, value,
  self list at(x) atPut(y, value)
)
 
Matrix get := method(x, y,
  self list at(x) at(y)
)
 
matrix := Matrix clone
matrix dim(4, 2)
 
matrix set(3, 1, "Hello")
matrix set(1, 1, "World")
 
matrix get(3, 1) println
matrix get(1, 1) println
Bonnus: write a transpose method so that new_matrix get(y, x) == matrix get(x, y) on the original list
Matrix transpose := method(
  x := self list at(0) size
  y := self list size
  m := Matrix clone
  m dim(x, y)
  for(i, 0, x - 1,
    for(j, 0, y - 1,
      m set(i, j, self get(j, i))
    )
  )
  m
)
 
new_matrix := matrix transpose
 
(matrix get(3, 1) == new_matrix get(1, 3)) println
Write the matrix to a file, read the matrix from a file.

For this one, decided to aggressively look in the List API to make the code simpler. I discovered quite a lot of useful functions! I also implemented the asString method so that it is easier to debug (the println method on the Object type is implemented to print the result of asString.)

Here is the full code for the whole Matrix object, improved as much as I could:

Matrix := Object clone
 
Matrix list := nil
 
Matrix dim := method(x, y,
  self list := List clone setSize(x)
  for(i, 0, x - 1,
    self list atPut(i, List clone setSize(y))
  )
)
 
Matrix set := method(x, y, value,
  self list at(x) atPut(y, value)
)
 
Matrix get := method(x, y,
  self list at(x) at(y)
)
 
Matrix transpose := method(
  x := self list at(0) size
  y := self list size
  m := Matrix clone
  m dim(x, y)
  for(i, 0, x - 1,
    for(j, 0, y - 1,
      m set(i, j, self get(j, i))
    )
  )
  return m
)
 
Matrix asString := method(
  s := ""
  self list foreach(e,
    s := s asMutable appendSeq(e join(",")) asMutable appendSeq("\n")
  )
)
 
Matrix saveTo := method(file,
  f := File with(file) remove openForUpdating
  self list foreach(i, e,
    f write(e join(",")) write("\n")
  )
  f close
)
 
Matrix loadFrom := method(file,
  l := List clone
  f := File with(file) openForReading
  f readLines foreach(e,
    l append(e splitNoEmpties(","))
  )
  f close
  m := Matrix clone
  m dim(l size, l at(0) size)
  l foreach(i, e,
    e foreach(j, f,
      m set(i, j, f)
    )
  )
  m
)
 
/* Tests */
matrix saveTo("matrix.txt")
new_matrix saveTo("new_matrix.txt")
 
matrix := Matrix loadFrom("matrix.txt")
new_matrix := Matrix loadFrom("new_matrix.txt")
 
matrix println
new_matrix println
Write a program that gives you 10 tries to guess a random number from 1 to 100. Give hints of “Hotter” or “Colder” if you like.
//Not really random, but will suffice for now
n := Date now second * 1000 % 100
 
input := File standardInput();
 
for(i, 1, 10,
  guess := input readLine asNumber
 
  if (guess &lt; n, "Hotter" println)
  if (guess &gt; n, "Colder" println)
  if (guess == n,
    "Well done!" println
    break
  )  
)

I really enjoyed myself with these! Looking forward to Day 3…

Io, Day 1

First day on Io, which I never heard about…

Io is a dynamic prototype-based programming language.

Apart from JavaScript, I never heard any other prototype-based language. And even in JavaScript, I don’t know exactly what this implies, so my expectation of learning new things while studying Io is quite high, which is good!

By the way, Io is the name of a nymph in Greek mythology and one of Jupiter’s satellite. Believe it or not, but I knew that before encountering the language, and still wonder if there is any relation whatsoever, but didn’t find anything about the language name’s origin…

Io

(to me it was the perfect excuse to put a picture of a sexy girl on my blog and get more traffic!)

Anyway, first task, get Io to run on my box, namely a Windows 7 x64 machine. After downloading the sources and trying to build them according to the readme.txt, lots of errors…

Finally, I found that the best solution is to download the binaries which work fine on my machine. That’ll do for now.

I also needed some reference to lookup to when in doubt, and that’s all available here.

So, on day one, no real assignments, or at least nothing that can’t be found in 30 seconds on the official website, so I’m not going to replicate this here.

Ruby, Day 3

Last day on Ruby!

Retrospectively, I didn’t knew Ruby before (and I still don’t know much about it, admittedly), but it’s been fun.

I’m not a big fan after what I saw. I still find it a bit messy, but that’s maybe because I’m not used to it enough. The “you can rewrite anything and change basic behavior” is very nice, but I seriously wonder how many times it has bitten back developers. If someone rewrites one of the basic methods in a big codebase, I can only imagine the consequences, if you are luck enough to see them right away…

However, I enjoyed scripting with Ruby very much, and it was a good brainteaser to try to find the effective way of doing those things in a language I completely ignored so far.

Anyway, here is my last homework!

Do

So, the goal here is to modify a class that reads CSV files and add an each method that will perform a block on a CsvRow object, object that is to be written. This object should have its method_missing overwritten so that you can access columns as if they were methods:

module ActsAsCsv
 
  def self.included(base)
    base.extend ClassMethods
  end
 
  module ClassMethods
    def acts_as_csv
      include InstanceMethods
    end
  end
 
  module InstanceMethods
 
    def read
      @csv_contents = []
      filename = self.class.to_s.downcase + '.csv'
      file = File.new(filename)
      @headers = file.gets.chomp.split(', ')
 
      file.each do |row|
        @csv_contents << row.chomp.split(', ')
      end
    end
 
    attr_accessor :headers, :csv_contents
 
    def initialize
      read 
    end
 
    def each(&block)
      @csv_contents.each { |line| block.call CsvRow.new(@headers, line) }
    end
 
  end
 
end
 
class RubyCsv  # no inheritance! You can mix it in
  include ActsAsCsv
  acts_as_csv
end
 
class CsvRow
  attr_accessor :headings, :values
 
  def initialize(headings, values)
    @headings = headings
    @values = Hash[headings.zip(values).map { |e| [e[0], e[1]] }]
  end
 
  def method_missing(name, *args)
    col = name.to_s
    @values[col]
  end
end
 
csv = RubyCsv.new
csv.each { |row| puts row.two }

Ruby, Day 2

Find

#File IO without block
#f = File.new("testfile", "r")
#f.close
 
#File IO with block, implicit call to f.close
#File.open("testfile", "r") do |aFile| end
 
#Hash to array
h = { 1 => 2, "cat" => "tom" }
a = h.to_a
 
#Array to hash
a = (1..10).to_a
h = Hash[a.map { |i| [i, i * 2] } ]
 
#Iterate through a hash
h.each { |i| puts "#{i[0]} : #{i[1]}" }
 
#Use array as stack
a.push 19
a.pop
 
#Arrays can be used as: stacks, sets, queues, dequeues, and fifos

Do

Print the content of an array of sixteen numbers, four numbers at a time, using just each. Now, do the same with each_slice in Enumerable:

#Using each (interesting fact: there is a closure on a here)
a.each { |i| if i % 4 == 0 then puts "#{a[i-4..i-1]}" end }
 
#Using each_slice 
a.each_slice(4) { |s| puts "#{s}" }

Rewrite the Tree class so it can be initialized with a nested structure with hashes and arrays:

#Initial code from the book
class Tree
  attr_accessor :children, :node_name
 
  def initialize(name, children=[])
    @children = children
    @node_name = name
  end
 
  def visit_all(&block)
    visit &block
    @children.each { |c| c.visit_all &block }
  end
 
  def visit(&block)
    block.call self
  end
end
 
t = Tree.new("Ruby", [Tree.new("Gem")])
t.visit_all { |t| puts "#{t.node_name}" }

Starting from that, this is what we want to be able to write:

Tree.new({ 'grandpa' => { 'dad' => { 'child 1' => {}, 'child 2' => {} }, 'uncle' => { 'child 3' => {}, 'child 4' => {} } } })

And here is my solution to it:

class Tree
  attr_accessor :children, :node_name
 
  def initialize(structure)
    structure.each do
      |key, value|
      @node_name = key
      @children = value.to_a.map { |e| Tree.new({ e[0] => e[1] }) }
    end
  end
 
  def visit_all(&block)
    visit &block
    @children.each { |c| c.visit_all &block }
  end
 
  def visit(&block)
    block.call self
  end
end
 
t = Tree.new({ 'grandpa' => { 'dad' => { 'child 1' => {}, 'child 2' => {} }, 'uncle' => { 'child 3' => {}, 'child 4' => {} } } })
t.visit_all { |t| puts "#{t.node_name}" }

Write a simple grep that will print the lines of a file having any occurrences of a phrase anywhere in that line. Use Regular Expressions and include line numbers:

regex = Regexp.new('sit amet')
ln = 0
 
IO.foreach("TestGrep.txt") do |line|
  ln = ln + 1
  puts "#{ln}: #{line}" if regex.match(line)
end

Next Page →