Does this make my code look big?

April 10, 2009

Real World Haskell Chapter 3 – Ruby

Filed under: Chapter 3,Code,Exercise,Ruby — Barry Allison @ 11:05 pm
Tags:

Chapter 3 exercise solutions.

The <=> method (the spaceship operator) is defined here to sort by y-coordinate and to choose the left-most in case of a match. This means that enumerations of Points can be sorted. This isn’t necessarily a good idea but it is suitable for finding the pivot point.

class Point
  attr_reader :x ,:y
  def initialize(x,y)
    @x = x
    @y = y
  end

  def <=>(other)
    return -1 if @y < other.y
    return  1 if @y > other.y
    return -1 if @x < other.x
    return  1 if @x > other.x
    0
  end

  def inspect()
    "(#{@x},#{@y})"
  end
end

An explicit inspect method is defined to make checking of results a bit easier on the eyes.

Ruby’s built in enumeration sorting is equivalent to Haskell’s sortBy strategy, either by writing a spaceship operator or passing a block to sort that returns a suitable value.

def sort_by_angle
  # 1. Find the origin or lowest point
  initial_sort = @vertices.sort
  origin = initial_sort[0]
  # 2. Sort all points by the angle each point makes with the origin
  [origin] + initial_sort[1..-1].sort! {|v, pivot| compare_angles(origin, v, pivot)}
end

def compare_angles(origin, p1, p2)
  p = (p1.x - origin.x)*(p1.y - p2.y)
  q = (p1.y - origin.y)*(p1.x - p2.x)
  return -1 if p < q
  return  1 if p > q
  return -1 if p1.y > p2.y
  return  1 if p1.y < p2.y
  0
end

April 1, 2009

Chapter 6 – Ruby supermarket

Filed under: Chapter 6,Code,Exercise,Ruby — Barry Allison @ 2:48 pm
Tags:

The different types introduced in the book translate into ruby classes and rather than have a monolithic single file with all the class definitions in them, the separate types are split into different files:

  • bill.rb The Bill class which has various methods for formatting bills scattered throughout the exercises like skipping unknown items and adding a discount item.
  • bill_item.rb The BillItem class which just stores name and price
  • till.rb – the Till class to store bar codes and methods to create different types of bills
  • database.rb – the Database class which stores a set of index items with methods to add and remove items
  • index.rb – the Index class which just stores a name price and bar code
  • supermarket.rb – the Supermarket class which has most of the exercise answers
  • analysis.rb -the Analysis class with the extra exercises to analyse sets of tills

I find writing in ruby to be more opaque and less flexible than scheme – I think because of the scheme repl. Ruby has irb which is great for testing out ideas and playing around with classes to test them but I mean that when something goes wrong it’s generally easier for me to isolate and fix the problem in scheme than in ruby. This could definitely be improved by adopting a proper test-driven approach but even so I still find it easier to break apart and work with small problem areas using scheme. Haskell is hardest of all – especially with type errors, but I’m expecting that to improve as I start to get more comfortable in haskell and get to know the Prelude and other libraries better.

One of the inherent problems I find with ruby is that of method scope and testing – should I mark methods private and hide them from the outside world – which makes testing them more difficult – or should I leave them all public and expose methods that have no right being used outside the scope of the class. I haven’t come up with a good heuristic for deciding the answer to that question yet. In some respects it’s a non-question due to the extremely dynamic nature of ruby – you can’t really hide anything, but still it feels right to signal to the world the intention that helper methods are private and not really to be used by the whole universe.

February 28, 2009

Chapter 6 – Ruby Geometry

Filed under: Chapter 6,Code,Exercise,Ruby — Barry Allison @ 8:53 pm
Tags:

Solutions to Chapter 6 geometry exercises.

Types

Since chapter 6 introduced types definitions, it seems appropriate to use classes in Ruby.
I defined the rotation and flip methods on the Image class with each one returning a new image object having been transformed in the appropriate manner. I did this rather than change the state of the image for a few reasons:

  • It’s closer to the functional paradigm and I like the idea of being able to repeat operations without changing the state of the objects involved. I find that this often makes testing easier, having to track state changes in tests can introduce complexity particularly in setting up test data.
  • One of the Ruby idioms is to name methods that affect state with a ! at the end for example "open".capitalize vs. "sesame".capitalize!.
    I can always add methods later that change the object’s state and name them e.g. rotate_naive! and so on
  • I like being able to chain method calls together such as i.rotate_geometric.move(5,3).print

I found I made more mistakes in the Ruby code and that it was harder to track down problems and test than both the Scheme and the Haskell versions. Here I think the scheme repl has the advantage – I’m using DrScheme as opposed to emacs for both Ruby and Haskell. Having to constantly reload files after making changes hampers my progress more than in DrScheme were there is no need to reload the file in the repl. It seems like a pretty weak argument but I find it faster and more efficient.

February 17, 2009

Chapter 5 – Ruby

Filed under: Chapter 5,Code,Exercise,Ruby — Barry Allison @ 7:15 pm
Tags:

Chapter 5 solutions

There are no list comprehensions in Ruby but most of the time blocks and Enumerable objects do the trick.
The trick being choosing whether to use map for unfiltered comprehensions, or inject, select, reject or something else for filtered comprehensions. Nested comprehensions could be a bit trickier though – I’ll wait and see if there are more complex nested examples later in the book.

A simple unfiltered comprehension just uses map

def double_all(xs)
  xs.map{ |x| 2 * x }
end

select can be used for inclusive filtered comprehensions with reject for exclusive filters.

def divisors(n)
  (1..n).select { |i| n % i == 0 }
end

Here though inject is needed rather than select because the object being yielded to the block is more complicated and thee whole thing isn’t being returned.
In a real life application though the objects being yielded into the block would probably have methods to return the desired results (the book in this case.)

def books(d_base, person)
  d_base.inject([]) { |loaned, loan| loan[0] == person ? loaned << loan[1] : loaned }
end

I think haskell wins at comprehensions though.

February 15, 2009

Chapter 4 – Ruby

Filed under: Chapter 4,Code,Exercise,Ruby — Barry Allison @ 2:31 pm
Tags:

Chapter 4 solution

The 2 main things of interest tackling chapter 4 in ruby are the use of recursion and the impedance mismatch handling functional arguments.

First, writing recursive methods is less common in ruby than scheme or haskell [citation needed]. I think there are a couple of reasons for that.First is the rich use of blocks in ruby – lots of recursive procedures can be replaced with blocks using an Enumerable object, and there are plenty of those in ruby. Compare the range_product method:

rangeProduct :: Int -> Int -> Int
rangeProduct x y
    | x > y     = error "rangeProduct start is greater than end"
    | x == y    = y
    | otherwise = x * rangeProduct (x+1) y

def range_product(x, y)
  raise "range_product start is greater than end value" if x > y
  (x..y).inject(1) {|prod, i| prod * i }
end

Creating an Enumerable range object and using inject – ruby’s fold equivalent is much more idiomatic than writing a recursive method.

Secondly there is no tail call optimisation in ruby – at least not in 1.8.6. (I think the 1.9 vm may introduce tail call optimisation). This means every recursive call builds up the call stack – which is fine on small levels of recursion but scheme guarantees tail call optimisation and the haskell compiler internally uses such optimisation where it can identify the need – I seem to remember reading that if the last line of code is a recursive call it will be optimised.

The use of functional arguments is pretty painful and inconsistent in ruby compared to both scheme and haskell. For example if I have an id method, I can’t just write 1 + sum_fum(id, n) in the way that is possible in scheme and haskell – which feels natural and intuitive. As far as I can tell there are 3 options:

  • Wrap the method invocation in a new Proc object – Proc.new {|x| id(x) }
  • Wrap the method invocation using a lambda generated Proc ojbject lambda {|x| id(x) }
  • Pass a block into the method invocation and have the method convert the block into a Proc object

The problem with these is they all behave differently Proc and lambda have different semantic behaviour when the invoked method uses a return statement. Using a block means the method being invoked has to generate a Proc object from the block passed in – admittedly that’s easy to do but the problem is having to remember all the subtle differences rather than just being able to use a single consistent mechanism for dealing with functional arguments. Here ruby is definitely lacking, obtuse and obscure.

February 6, 2009

Chapter 3 – Ruby

Filed under: Chapter 3,Code,Exercise,Ruby — Barry Allison @ 11:20 am
Tags:

Chapter 3 solutions

I’m using Ruby 1.8.6 for these exercises and the unicode support is notoriously lacking and so I expected strange results. Still not worse than the haskell.

capitalise "Straße" -> "STRA303237E" and the built in gives the same result:
"Straße".upcase -> "STRA303237E"

Again I’m using a split on the string in order to get an Enumerable so I can then use the built in fold method inject.

def capitalise(s)
  # s.upcase
  offset = "a"[0] - "A"[0]
  s.split(//).inject("") { |up, c| up << ((c  "z") ? c : (c[0]-offset).chr)}
end

February 4, 2009

Chapter 2 – Ruby

Filed under: Chapter 2,Code,Exercise,Ruby — Barry Allison @ 5:52 pm
Tags:

Ruby solutions for chapter 2

require 'pictures.rb'
include Pictures

module UsePictures
:private
  def self.chequer(p1, p2)
    above(side_by_side(p1, p2), side_by_side(p2, p1))
  end

  def self.make_hatch
    row = side_by_side(White, Black)
    above(row, invert_colour(row))
  end

  def self.chess_board
    quarter = chequer(Hatch, Hatch)
    chequer(quarter, quarter)
  end

  def self.rotate(pic)
    flip_v(flip_h(pic))
  end

  def self.rotate_horse
    rotate(Horse)
  end
:public
  BlackHorse  = invert_colour(Horse)
  Black       = invert_colour(White)
  Black2      = superimpose(Horse, (invert_colour Horse))
  Hatch       = above(side_by_side(White, Black), side_by_side(Black, White))
  Hatch2      = make_hatch
  Chess       = chess_board
  HorseHatch1 = above(side_by_side(Horse, Black), side_by_side(Black, Horse))
  HorseHatch2 = above(side_by_side(Horse, Black), side_by_side(Black, flip_v(Horse)))
  HorseHatch3 = above(side_by_side(Horse, Black), side_by_side(Black, rotate(Horse)))
  HorseHatch4 = above(side_by_side(Horse, Black), side_by_side(Black, flip_h(Horse)))
end

In order to use the functions when defining the picture constants I had to declare the functions first, but I don’t really want to export them from the module so they are declared :private

I think all of the ruby code I’ve seen before puts the private declarations at the end of the file. Ruby is famously reflective and allows classes to be opened, but I’m not sure about modules. I need to look closer into this – is it worth trying to hide definitions in modules?

January 25, 2009

Exercise 2.1 – starting out with pictures

Filed under: Chapter 2,Code,Exercise,Haskell,Ruby,Scheme — Barry Allison @ 6:06 pm
Tags:

Before starting on the exercises in chapter 2, I need to translate the “library” functions in Picture.hs into the relevant languages; I’ll leave compiling and accessing foreign libraries for another day ;)
Here are the Scheme and Ruby versions I’m going to use.

Answers: ex02.01.hs, ex02.01.rb, ex02.01.ss

A note on strings. I found the built-in string handling abilities of all of them to be quirky or lacking.

Scheme. There’s a string-map in SRFI 13, but unlike the regular map it doesn’t accept multiple arguments so I wrote a specialised version that dealt with two input strings. Note to self: extend that to accept an arbitrary number of  strings to another day. Or you could do that and send me the results.

Ruby. I wrote this to target 1.8.6 so 1.9 may have addressed this but it seems natural to me to write "string".each and have that enumerate the characters of the string.
Instead I used the uglier "string".split(//).each. I can see that string handling in the era of unicode is difficult but this just feels awkward and inconsistent. I might consider writing a charmap method and add it to the string class that does exactly that.

Haskell. I really like the rational approach haskell takes treating a string as a list of chars. It’s so nice to be able to write things like 'b':"ad"  "Con" ++ "cat" and use map, fold, filter et al.

Theme: Rubric. Blog at WordPress.com.

Follow

Get every new post delivered to your Inbox.