timr wrote:
Hi Rubyists,
I love ruby, but am learning scheme and kinda like the (cond
((assertion) (value))…(else (value))) syntax
I am a little bit confused by your question. In the subject line you
are asking about a Ruby equivalent to Scheme’s ‘cond’ statement. But
AFAIK, Scheme doesn’t have statements, it only has epxressions and
definitions.
If you are looking for an equivalent of the ‘cond’ derived conditional
expression, then Ruby has something which is exactly equivalent
(modulo the guarantees about proper tail calls) to the specification
in clause 11.4.5 of the 6th Revised Report on the Algorithmic Language
Scheme: the “‘case’ expression without expression” (which is quite a
mouthful …)
case
when <test> then <expression>
when <test>
<expression>
<expression>
else
<expression>
end
I find scheme’s cond syntax more quickly digestible since it reads
like a table.
(cond
((assertion 1) (value 1))
((assertion 2) (value 2))
(else (default)))
That’s equivalent (again, modulo tail context guarantees) to
case
when assertion 1 then value 1
when assertion 2 then value 2
else default
end
tests.each_pair do |k,v|
end
cond l{3 < 2} => l{ puts “3 is less than 2”},
l{3 > 3} => l{ puts “3 is greater than 3”},
l{3+1 > 4} => l{ puts “4 is greater than 4”},
end_cond => l{ puts “hey, it works!”}
>> hey, it works!
AFAICS, this does not behave like either Scheme’s ‘cond’ or Ruby’s
‘case’ expression without expression. In particular, it doesn’t seem
to return the value of the evaluated consequence expression. Instead,
it simply returns the hash that was passed in, which doesn’t seem
particularly useful to me.
This seems to be closer to what you are looking for:
class Object
private
def cond(conds)
conds.each {|t, e| if t.is_a?(Proc) then t.() else t end and
return e.() }
end
end
puts cond ->{ 3 < 2 } => ->{ '3 is less than 2' },
->{ 3 > 3 } => ->{ '3 is greater than 3' },
->{ 3+1 > 4 } => ->{ '4 is greater than 4' },
else: ->{ 'hey, it works!' }
I was surprised that the hash seems not to mix-up the order of the k:v
pairs like it would if the keys were strings or symbols. I suppose
because they are lambda’s, the hash doesn’t bother alphabetizing them
during for the .each_pair method. Since they stay ordered, this table-
like if;elsif;else seems to work fine. Can anyone think of any issues
to using this approach? Can it give rise to unpredicted values–due to
some behind the curtain hash key sorting?
In Ruby 1.9, hashes are always guaranteed to be ordered by insertion.
In Ruby 1.8, hashes are always unordered, regardless of whether their
keys are symbols, strings, procs or unicorns.
Or can anyone come up with a cleaner syntax than a hash of lambdas for
both keys and values?
In Ruby 1.9, I think it is just fine. In Ruby 1.8, you would have to
use something which is ordered, like an array, or you would have to
require that the branches are mutually exclusive, which of course
rules out the possiblity of an ‘else’ branch.
What I am not entirely clear about is what’s wrong with
puts case
when 3 < 2 then '3 is less than 2'
when 3 > 3 then '3 is greater than 3'
when 3+1 > 4 then '4 is greater than 4'
else 'hey, it works!'
end
That looks just fine to me.
Another thing that bugs me is that Ruby is an object-oriented
language, but I don’t see an obvious object that the cond method
should belong to.
jwm