Not infrequently, one wants to implement the <=> (comparison, or "spaceship") operator on a product data type, i.e., a class with multiple fields (all of which (we hope!) already have <=> implemented), comparing the fields in a certain order.
def <=>(o)
f1 < o.f1 && (return -1)
f1 > o.f1 && (return 1)
f2 < o.f2 && (return -1)
f2 > o.f2 && (return 1)
return 0
end
This is both tedious and error-prone, especially with a lot of fields. It's error-prone enough that I frequently feel I should unit test that function, which just adds to the tediousness and verbosity.
Haskell offers a particularly nice way of doing this:
import Data.Monoid (mappend)
import Data.Ord (comparing)
-- From the standard library:
-- data Ordering = LT | EQ | GT
data D = D { f3 :: Int, f2 :: Double, f1 :: Char } deriving Show
compareD :: D -> D -> Ordering
compareD = foldl1 mappend [comparing f1, comparing f2, comparing f3]
(For those not familiar with fold, the above expands to
comparing f1 `mappend` comparing f2 `mappend` comparing f3
which produces a function that can be applied to two Ds, to produce an Ordering.)
The defintion of compareD is so simple that it's obviously correct, and I wouldn't feel the need to unit test it even without static type checking.
Actually, the question may be even slightly more interesting than this, since I may not want to use just the standard <=> operator, but sort in different ways at different times, e.g.:
sortByOrderings :: [a -> a -> Ordering] -> [a] -> [a]
sortByOrderings = sortBy . foldl1 mappend
sortByF3F1 = sortByOrderings [comparing f3, comparing f1]
sortByF2F3 = sortByOrderings [comparing f2, comparing f3]
So, the questions:
What's the typical way of implementing this sort of thing in Ruby?
What's the nicest way of doing it using just what's defined in the standard libraries?
How close can one get to the Haskell code above, and how reliable is it, in comparison? If necessary, how can one ensure that the fields have a properly implemented <=> or < and > operators?
Incidently, while this is a Ruby question, I'm happy to consider discussion of the Haskell techniques on-topic if the elders of this site so agree. Please feel free to comment on whether that's appropriate or not and, if it is, tag this post 'haskell' as well.
Here's what I do to make custom sorting rules more manageable: on all my classes I ever need to sort, I define "to_sort" methods that return arrays, and then override <=> to use to_sort:
class Whatever
def to_sort
[#mainkey,#subkey,#subsubkey]
end
def <=>(o)
self.to_sort <=> o.to_sort
end
end
Thus sorting any array of Whatevers (including heterogeneous arrays of Whatevers and Whateverothers and Whathaveyours, all of which implement type-specific to_sort functions and this same <=> override) just devolves internally to sorting an array of arrays.
Here's a riff on your idea. It doesn't define any extra constants, allows you to use any combination of instance variables and methods to compare two objects, has early exit on not-equal, and includes all the methods defined by Comparable.
class Object
def self.compare_by(*symbols)
include Comparable
dispatchers = symbols.map do |symbol|
if symbol.to_s =~ /^#/
lambda { |o| o.instance_variable_get(symbol) }
else
lambda { |o| o.__send__(symbol) }
end
end
define_method('<=>') do |other|
dispatchers.inject(0) do |_,dispatcher|
comp = dispatcher[self] <=> dispatcher[other]
break comp if comp != 0
comp
end
end
end
end
class T
def initialize(name,f1,f2,f3)
#name,#f1, #f2, #f3 = name,f1, f2, f3;
end
def f1
puts "checking ##name's f1"
#f1
end
def f3
puts "checking ##name's f3"
#f3
end
compare_by :f1, :#f2, :f3
end
w = T.new('x',1,1,2)
x = T.new('x',1,2,3)
y = T.new('y',2,3,4)
z = T.new('z',2,3,5)
p w < x #=> checking x's f1
# checking x's f1
# true
p x == y #=> checking x's f1
# checking y's f1
# false
p y <= z #=> checking y's f1
# checking z's f1
# checking y's f3
# checking z's f3
# true
If you wanted, you could insert some extra error checking in there to make sure that
the values used to compare actually respond to <=> (using respond_to? '<=>'), and try to
give clearer error messages in the case wwhere they don't.
I took a similar approach as rampion, but wanted to handle the case where attributes could be nil.
module ComparableBy
def comparable_by(*attributes)
include Comparable
define_method(:<=>) do |other|
return if other.nil?
attributes.each do |attribute|
left = self.__send__(attribute)
right = other.__send__(attribute)
return -1 if left.nil?
return 1 if right.nil?
comparison = left <=> right
return comparison unless comparison == 0
end
return 0
end
end
end
Example Usage:
SomeObject = Struct.new(:a, :b, :c) do
extend ComparableBy
comparable_by :a, :b, :c
end
Well, here's a quick hack at an extension to Object to make this happen in what seems to be a reasonably nice way.
class Object
def self.spaceship_uses(*methods)
self.const_set(:SPACESHIP_USES, methods)
end
def <=>(o)
raise(NoMethodError, "undefined method `<=>' for #{self.inspect}") \
unless self.class.const_defined?(:SPACESHIP_USES)
self.class.const_get(:SPACESHIP_USES).each { |sym|
self.send(sym) < o.send(sym) && (return -1)
self.send(sym) > o.send(sym) && (return 1)
}
return 0
end
end
class T
def initialize(f1, f2) #f1, #f2 = f1, f2; end
attr_reader :f1, :f2
spaceship_uses :f1, :f2
end
This of course doesn't deal with any typing issues, to make sure that < and > are properly implemented for the objects returned by the methods in SPACESHIP_USES. But then gain, being Ruby, this is probably fine, isn't it?
Short comments can comment on this, but I'd be interested in seeing detailed discussion and extensions in other answers.
Related
I am toying around with Ruby to learn the language. Currently I'm trying to wrap my head around the concept of fibers. According to this answer, they are fairly often used for creating (infinite) external enumerators. On the other hand, this seems to overlap with the concept of so called explicit enumerators.
Say, I want to write a code snippet that fires consecutive prime numbers (yes, the following algorithm has a runtime of O(scary)). I can implement it by using fibers:
prime_fiber = Fiber.new do
primes = [2]
Fiber.yield 2
current = 1
loop do
current += 2
unless primes.find {|value| (current % value) == 0}
Fiber.yield current
primes << current
end
end
end
ARGV[0].to_i.times {print "#{prime_fiber.resume}, "}
This does not emit an enumerator object by itself, although it is not difficult to create one out of it. In contrast, I can also utilize an explicitly defined enumerator, which has the added benefit of already being an enumerator object:
prime_enum = Enumerator.new do |yielder|
primes = [2]
yielder.yield 2
current = 1
loop do
current += 2
unless primes.find {|value| (current % value) == 0}
yielder.yield current
primes << current
end
end
end
ARGV[0].to_i.times {print "#{prime_enum.next}, "}
# I could also write:
# p prime_enum.first(ARGV[0].to_i)
Both methods allow me to implement some sort of co-routines and they seem to be interchangeable to me. So when do I prefer one over the other? Is there some commonly agreed practice? I find it difficult to get all those idioms in my head, so I apologize in advance if this is considered a dumb question.
I would use Enumerator, it allows you to use take, take_while, even each if your sequence is finite. While Fiber is designed for light weight concurrency and is pretty limited as enumerator.
prime_enum.take(ARGV[0].to_i).each { |x| puts x }
or
prime_enum.take_while { |x| x < ARGV[0].to_i }.each { |x| puts x }
I have a piece of code in Ruby which goes as follows:
def check
if a == b || c == b
# execute some code
# b = the same variable
end
end
can this be written like
def check
if a || c == b
# this doesn't do the trick
end
if (a || c) == b
# this also doesn't do the magic as I thought it would
end
end
Or in a manner where I don't need to type b twice. This is out of laziness and I would like to know.
if [a, c].include? b
# code
end
This is, however, significantly slower than the code you want to avoid -- at least as long as a, b and c are basic data. My measurements showed a factor of 3. This is probably due to the additional Array object creation. So you might have to weigh DRY against performance here. Normally it should not matter, though, because both variants do not take long.
While not an exact equivalent of a == b || a == c, case statement offers syntax for this:
case a
when b, c then puts "It's b or c."
else puts "It's something else."
end
Feel free to opent the nearest Ruby textbook and read about how case statement works. Spoiler: It works by calling #=== method on the compared objects:
a = 42
b, c = Object.new, Object.new
def b.=== other; puts "b#=== called" end
def c.=== other; puts "c#=== called" end
Now run
case a
when b, c then true
else false end
This gives you a lot of flexibility. It requires work in the back office, but after you do it, looks like magic in the front office.
You should really know why this doesn't work:
(a || c) == b
This seems like a translation of the sentence "a or c is equal b", which makes sense in English.
In almost all programming languages, (a || c) is an expression, whose evaluated result will be compared to b. The translation to English is "The result of the operation "a or c" is equal to b".
#undur_gongor's answer is perfectly correct. Just to add though, if you're working with arrays, for example:
a = [1,2,3]
c = [4,5,6]
b = [5,6]
if [a, c].include? b
# won't work if your desired result is true
end
You'd have to do something like:
if [a,c].any?{ |i| (i&b).length == b.length }
# assuming that you're always working with arrays
end
# otherwise ..
if [a,c].any?{ |i| ([i].flatten&[b].flatten).length == [b].flatten.length }
# this'll handle objects other than arrays too.
end
What about this?
if [a,c].index(b) != nil;puts "b = a or b = c";end
Acolyte pointed out you can use b == (a||c), you just had it backwards, but that only works for the left value, since (a||c) is always a, assuming a isn't falsey.
Another option is to use a ternary operator.
a==b ? true : b==c
I'm not sure of the speed difference cited wrt the array approach, but I would think this could be faster since it's doing either one or two comparisons and doesn't need to deal with arrays. Also, I assume it's the exact same as (a==b || b==c), but it's a stylistic alternative.
When programming ruby I always find myself doing this:
a = [a, b].min
This means compare a and b and store the smallest value in a. I don't like writing the code above as I have to write a twice.
I know that some non-standard dialects of C++ had an operator which did exactly this
a <?= b
Which I find very convenient. But I'm not really interested in the operator as much as I'm in the feature of avoiding repetition. I would also be happy if I could write
a.keep_max(b)
a can be a quite long variable, like my_array[indice1][indice2], and you don't want to write that twice.
I did alot of googling on this and found no result, hopefully this question will pop up and be useful for others aswell.
So, is there any non-repeitive way to express what I want in ruby?
What you would like to do is in fact not possible in ruby (see this question). I think the best you can do is
def max(*args)
args.max
end
a = max a, b
I don't understand your question. You can always do something like this ...
module Comparable
def keep_min(other)
(self <=> other) <= 0 ? self : other
end
def keep_max(other)
(self <=> other) >= 0 ? self : other
end
end
1.keep_min(2)
=> 1
1.keep_max(2)
=> 2
Well, that won't work for all objects with <=> because not all of them are implementing Comparable, so you could monkey-patch Object.
Personally I prefer clarity and tend to avoid monkey-patching. Plus, this clearly is a binary predicate, just like "+", therefore method-chaining doesn't necessarily make sense so I prefer something like this to get rid of that array syntax:
def min(*args)
args.min
end
def max(*args)
args.max
end
min(1, 2)
=> 1
max(1, 2)
=> 2
But hey, I'm also a Python developer :-)
You can define your own method for it:
class Object
def keep_max(other)
[self, other].max
end
end
a = 3
b = 7
puts a.keep_max(b)
But you should be careful defining methods on Object as it can have unpredictable behaviour (for example, if objects cannot be compared).
def keep_max(var, other, binding)
eval "#{var} = [#{var}, #{other}].max", binding
end
a = 5
b = 78
keep_max(:a, :b, binding)
puts a
#=> 78
This basically does what you want. Take a look at Change variable passed in a method
I have an array of arrays, called guid_pairs:
[['a','b','c'],['c','g'],['z','f','b']]
I also have an array, called array_to_check:
['c','a','b']
How can I determine if the array guid_pairs has an element that is equal to array_to_check. Equality should not consider the position of the array elements.
In this example, the check should return true because guid_pairs contains the element ['a','b','c'], which matches ['c','a','b'].
I have tried this, but it seems to always return false even when it should return true:
guid_pairs.any?{|pair| pair.eql?(array_to_check)}
I am using Ruby 1.9.2
There is a set class in the standard library and using sets nicely matches your intent:
require 'set'
a = ['c','a','b']
aa = [['a','b','c'],['c','g'],['z','f','b']]
find_this = Set.new(a)
the_match = aa.find { |x| find_this == Set.new(x) }
That will leave the matching element element of aa in the_match. If you're only interested in existence then you can simply check the truthiness of the_match; or use any? (thanks for the reminder Michael Kohl, I often forget about some of the things in Enumerable):
aa.any? { |x| find_this == Set.new(x) }
No tricks, no magic, and using Set makes it clear that you are, in fact, comparing the arrays as sets.
BTW, your attempted solution:
guid_pairs.any? { |pair| pair.eql?(array_to_check) }
doesn't work because arrays compare element-by-element in order so two arrays are equal if and only if they have equal elements in the same order. The documentation for eql? could be clearer:
Returns true if self and other are the same object, or are both arrays with the same content.
But the == documentation is nice and clear:
Two arrays are equal if they contain the same number of elements and if each element is equal to (according to Object.==) the corresponding element in the other array.
We can look to Object#eql? for some clarification though:
The eql? method returns true if obj and anObject have the same value. Used by Hash to test members for equality. For objects of class Object, eql? is synonymous with ==. Subclasses normally continue this tradition, but there are exceptions.
So == and eql? should behave the same way unless there is a good reason for them to be different.
To see if two arrays contain the same elements, regardless of order, you can use the XOR (exclusive or) operation. It will return an array which contains only elements that are in one array and not the other. If the length of the XOR is zero then the input arrays contain the same elements.
def xor(a, b)
(a | b) - (a & b)
end
guid_pairs.any? { |pair| xor(pair, array_to_check).length != 0 }
A possible solution is to sort the arrays before comparing (or even during comparing):
guid_pairs.any?{|pair| pair.sort.eql?(array_to_check.sort)}
Note that this may not be an optimal solution - it would be more appropriate to have your arrays sorted (nevertheless they are sets in your use case).
for equality of two arrays A and B i normally use:
if(((A-B) + (B-A)).blank?)
puts "equal"
else
"unequal"
end
You can use the following:
sorted_array_to_check = array_to_check.sort
guid_pairs.any?{|pair| pair.sort.eql?(sorted_array_to_check)}
Three solutions:
class Array
def check1 other; other.any?{|e| self - e == e - self} end
def check2 other; other.any?{|e| self | e == self and e | self == e} end
def check3 other; other.any?{|e| self & e == self and e & self == e} end
end
array_to_check.check1(guid_pairs) # => true
array_to_check.check2(guid_pairs) # => true
array_to_check.check3(guid_pairs) # => true
Without defining a method (following Josha's suggestion):
array_to_check.instance_eval{guid_pairs.any?{|e| self - e == e - self}} # => true
array_to_check.instance_eval{guid_pairs.any?{|e| self | e == self and e | self == e}} # => true
array_to_check.instance_eval{guid_pairs.any?{|e| self & e == self and e & self == e}} # => true
What would an equivalent construct of a monad be in Ruby?
The precise technical definition: A monad, in Ruby, would be any class with bind and self.unit methods defined such that for all instances m:
m.class.unit[a].bind[f] == f[a]
m.bind[m.class.unit] == m
m.bind[f].bind[g] == m.bind[lambda {|x| f[x].bind[g]}]
Some practical examples
A very simple example of a monad is the lazy Identity monad, which emulates lazy semantics in Ruby (a strict language):
class Id
def initialize(lam)
#v = lam
end
def force
#v[]
end
def self.unit
lambda {|x| Id.new(lambda { x })}
end
def bind
x = self
lambda {|f| Id.new(lambda { f[x.force] })}
end
end
Using this, you can chain procs together in a lazy manner. For example, in the following, x is a container "containing" 40, but the computation is not performed until the second line, evidenced by the fact that the puts statement doesn't output anything until force is called:
x = Id.new(lambda {20}).bind[lambda {|x| puts x; Id.unit[x * 2]}]
x.force
A somewhat similar, less abstract example would be a monad for getting values out of a database. Let's presume that we have a class Query with a run(c) method that takes a database connection c, and a constructor of Query objects that takes, say, an SQL string. So DatabaseValue represents a value that's coming from the database. DatabaseValue is a monad:
class DatabaseValue
def initialize(lam)
#cont = lam
end
def self.fromQuery(q)
DatabaseValue.new(lambda {|c| q.run(c) })
end
def run(c)
#cont[c]
end
def self.unit
lambda {|x| DatabaseValue.new(lambda {|c| x })}
end
def bind
x = self
lambda {|f| DatabaseValue.new(lambda {|c| f[x.run(c)].run(c) })}
end
end
This would let you chain database calls through a single connection, like so:
q = unit["John"].bind[lambda {|n|
fromQuery(Query.new("select dep_id from emp where name = #{n}")).
bind[lambda {|id|
fromQuery(Query.new("select name from dep where id = #{id}"))}].
bind[lambda { |name| unit[doSomethingWithDeptName(name)] }]
begin
c = openDbConnection
someResult = q.run(c)
rescue
puts "Error #{$!}"
ensure
c.close
end
OK, so why on earth would you do that? Because there are extremely useful functions that can be written once for all monads. So code that you would normally write over and over can be reused for any monad once you simply implement unit and bind. For example, we can define a Monad mixin that endows all such classes with some useful methods:
module Monad
I = lambda {|x| x }
# Structure-preserving transform that applies the given function
# across the monad environment.
def map
lambda {|f| bind[lambda {|x| self.class.unit[f[x]] }]}
end
# Joins a monad environment containing another into one environment.
def flatten
bind[I]
end
# Applies a function internally in the monad.
def ap
lambda {|x| liftM2[I,x] }
end
# Binds a binary function across two environments.
def liftM2
lambda {|f, m|
bind[lambda {|x1|
m.bind[lambda {|x2|
self.class.unit[f[x1,x2]]
}]
}]
}
end
end
And this in turn lets us do even more useful things, like define this function:
# An internal array iterator [m a] => m [a]
def sequence(m)
snoc = lambda {|xs, x| xs + [x]}
lambda {|ms| ms.inject(m.unit[[]], &(lambda {|x, xs| x.liftM2[snoc, xs] }))}
end
The sequence method takes a class that mixes in Monad, and returns a function that takes an array of monadic values and turns it into a monadic value containing an array. They could be Id values (turning an array of Identities into an Identity containing an array), or DatabaseValue objects (turning an array of queries into a query that returns an array), or functions (turning an array of functions into a function that returns an array), or arrays (turning an array of arrays inside-out), or parsers, continuations, state machines, or anything else that could possibly mix in the Monad module (which, as it turns out, is true for almost all data structures).
To add my two cents, I'd say that hzap has misunderstood the concept of monads.
It's not only a « type interface » or a « structure providing some specific functions », it's muck more than that.
It's an abstract structure providing operations (bind (>>=) and unit (return)) which follow, as Ken and Apocalisp said, strict rules.
If you're interested by monads and want to know more about them than the few things said in these answers, I strongly advise you to read : Monads for functional programming (pdf), by Wadler.
See ya!
PS: I see I don't directly answer your question, but Apocalisp already did, and I think (at least hope) that my precisions were worth it
Monads are not language constructs. They're just types that implement a particular interface, and since Ruby is dynamically typed, any class that implement something like collect in arrays, a join method (like flatten but only flattens one level), and a constructor that can wrap anything, is a monad.
Following on the above answers:
You may be interested in checking out Rumonade, a ruby gem which implements a Monad mix-in for Ruby.
Romande is implemented as mix-in, so it expect its host class to implement the methods self.unit and #bind (and optionally, self.empty), and will do the rest to make things work for you.
You can use it to map over Option, as you are used to in Scala, and you can even get some nice multiple-failure return values from validations, a la Scalaz's Validation class.