Skip to content

Instantly share code, notes, and snippets.

@pzol
Created June 25, 2012 07:45
Show Gist options
  • Star 3 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save pzol/2987218 to your computer and use it in GitHub Desktop.
Save pzol/2987218 to your computer and use it in GitHub Desktop.
Monadic vs Imperative code in ruby

Monadic vs Imperative

Here is a comparison of two pieces of code that do basically the same thing.

So what we have here is a chain of functions depending on each other, each consecutive takes the result of the previous one for further processing. If either of them fails, the rest shall not be executed.

  1. validate parameters received from the outside world in a Hash
  2. convert one of the parameters into an object
  3. do a search in the database

You could express the whole operation like this:

find_in_db(convert_to_bson_id(get_id( params )))

The important thing is, I assume using a debugger (also sometime puts-driven-development) an expensive operation on the human side, and hence should be avoided. The implication is, that each operation needs to report errors in a clean and predictive way.

You can find more examples and a description of the monadic stuff (Try, Either) used here https://github.com/pzol/monadic

module Transaction
# @return [Hash, nil]
def self.fetch_imp(params)
raise ArgumentError, 'params must be hash and contain id' unless params.is_a? Hash && params.has_key?('id')
id = params['id']
begin
bson_id = BSONTestConverter.from_string(id)
DatabaseReader.find(v)
rescue InvalidBSONString
raise ArgumentError, "'#{id}' is not a valid BSON id"
rescue SomeDatabaseError => dberror # just for the record
raise SomeDatabaseError, "#{dberror.message}: '#{id}' not found"
end
end
end
module Transaction
# @return [Success, Failure]
def self.fetch(params)
id = Maybe(params)['id']
Either(id).else('id is missing').
>= {|id| Try { BSONTestConverter.from_string(id) }.or("'#{id}' is not a valid BSON id") }.
>= {|id| Try { DatabaseReader.find(id) }.or("'#{id}' not found") }
end
end
module Transaction
def self.fetch2(params)
id = Maybe(params)['id']
Either(id).else('id is missing').
bind {|id| id_to_bson(id) }.
bind {|id| find_in_db(id) }
end
def self.id_to_bson(id)
Try { BSONTestConverter.from_string(id) }.or("'#{id}' is not a valid BSON id")
end
def self.find_in_db(bson_id)
Try { DatabaseReader.find(bson_id) }.or("'#{bson_id}' not found")
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment