Scheme's (cond ((assertion) (value))...(else (value))) statement implemented in ruby?

Hi Rubyists,
I love ruby, but am learning scheme and kinda like the (cond
((assertion) (value))...(else (value))) syntax for what would normally
look like this in ruby:

if (assertion 1)
  value 1
elsif (assertion 2)
  value 2
else
  default
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)))

So I wondered if I could get a similar looking function in ruby. Here
is an attempt:

class Object
  alias l lambda

  def cond(tests)
    #acts similar to scheme/LISP cond function using hash
    #key => value rather than scheme's (cond (assertion)(value)...
(else(value)))
    tests.each_pair do |k,v|
      if k.call
        v.call
        break
      else
        next
      end
    end
  end

  def end_cond; l{true}; end
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!

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? Or can anyone come up with a
cleaner syntax than a hash of lambdas for both keys and values? I know
this is not idiomatic ruby here. I am just having fun.

timr wrote:

Hi Rubyists,
I love ruby, but am learning scheme and kinda like the (cond
((assertion) (value))...(else (value))) syntax for what would normally
look like this in ruby:

if (assertion 1)
  value 1
elsif (assertion 2)
  value 2
else
  default
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)))

What's wrong with this?

x = 3
case
when x == 2; puts 'two'
when x == 3; puts 'three'
else puts 'other'
end

Clifford Heath.

How about chaining ternary operators?

3 < 2 ? puts("3 is less than 2") :
3 > 3 ? puts("3 is greater than 3") :
3+1 > 4 ? puts("4 is greater than 4") :
          puts("hey, it works!")

···

On Thu, Nov 11, 2010 at 7:20 PM, timr <timrandg@gmail.com> wrote:

Hi Rubyists,
I love ruby, but am learning scheme and kinda like the (cond
((assertion) (value))...(else (value))) syntax for what would normally
look like this in ruby:

if (assertion 1)
value 1
elsif (assertion 2)
value 2
else
default
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)))

So I wondered if I could get a similar looking function in ruby. Here
is an attempt:

class Object
alias l lambda

def cond(tests)
   #acts similar to scheme/LISP cond function using hash
   #key => value rather than scheme's (cond (assertion)(value)...
(else(value)))
   tests.each_pair do |k,v|
     if k.call
       v.call
       break
     else
       next
     end
   end
end

def end_cond; l{true}; end
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!

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

for what would normally
look like this in ruby:

if (assertion 1)
  value 1
elsif (assertion 2)
  value 2
else
  default
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

So I wondered if I could get a similar looking function in ruby. Here
is an attempt:

class Object
  alias l lambda

  def cond(tests)
    #acts similar to scheme/LISP cond function using hash
    #key => value rather than scheme's (cond (assertion)(value)...
(else(value)))
    tests.each_pair do |k,v|
      if k.call
        v.call
        break
      else
        next
      end
    end
  end

  def end_cond; l{true}; end
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

Case interrogates a single variable for its state--whether it falls in
a certain range, or is equal to such and such a value. The cond
statement is much more flexible, in that each assertion can be
completely unrelated to the other assertions--i.e. they can cover more
than the state of a single variable.

cond l{Store.open_time..Store.close_time === Time.now}
=>l{Store.access = true},
     l{after_hours_users.include? User.name}
=>l{Store.access = true},
     cond_end
=>l{Store.access = false; User.rain_check(1)}

In the above code access is given to anyone during store hours, but if
it is not during store hours and the user is listed as an
after_hours_user, they are allowed acces. If they can't get in because
it is after hours and they are not listed as an after_hours_user, they
are denied access but given a rain_check.

You can't do this kind of complex functionality with case, which only
inquires with regards to one variable.
Tim

···

On Nov 11, 5:51 pm, Clifford Heath <n...@spam.please.net> wrote:

timr wrote:
> Hi Rubyists,
> I love ruby, but am learning scheme and kinda like the (cond
> ((assertion) (value))...(else (value))) syntax for what would normally
> look like this in ruby:

> if (assertion 1)
> value 1
> elsif (assertion 2)
> value 2
> else
> default
> 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)))

What's wrong with this?

x = 3
case
when x == 2; puts 'two'
when x == 3; puts 'three'
else puts 'other'
end

Clifford Heath.

Woa, that is slick!

···

On Nov 12, 4:42 am, Josh Cheek <josh.ch...@gmail.com> wrote:

[Note: parts of this message were removed to make it a legal post.]

On Thu, Nov 11, 2010 at 7:20 PM, timr <timra...@gmail.com> wrote:
> Hi Rubyists,
> I love ruby, but am learning scheme and kinda like the (cond
> ((assertion) (value))...(else (value))) syntax for what would normally
> look like this in ruby:

> if (assertion 1)
> value 1
> elsif (assertion 2)
> value 2
> else
> default
> 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)))

> So I wondered if I could get a similar looking function in ruby. Here
> is an attempt:

> class Object
> alias l lambda

> def cond(tests)
> #acts similar to scheme/LISP cond function using hash
> #key => value rather than scheme's (cond (assertion)(value)...
> (else(value)))
> tests.each_pair do |k,v|
> if k.call
> v.call
> break
> else
> next
> end
> end
> end

> def end_cond; l{true}; end
> 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!

How about chaining ternary operators?

3 < 2 ? puts("3 is less than 2") :
3 > 3 ? puts("3 is greater than 3") :
3+1 > 4 ? puts("4 is greater than 4") :
puts("hey, it works!")

Perhaps you didn't notice the beginning of the code, where you find
the def for cond within the Object class.

class Object
  alias l lambda
  def cond(tests)
    #acts similar to scheme/LISP cond function using hash
    #key => value rather than scheme's (cond (assertion)(value)...
(else(value)))
    tests.each_pair do |k,v|
      if k.call
        v.call
        break
      else
        next
      end
    end
  end
  def end_cond; l{true}; end
end

···

On Nov 12, 6:14 am, Jörg W Mittag <JoergWMittag+R...@GoogleMail.Com> wrote:

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 &lt;test&gt; then &lt;expression&gt;
when &lt;test&gt;
  &lt;expression&gt;
  &lt;expression&gt;
else
  &lt;expression&gt;
end

> for what would normally
> look like this in ruby:

> if (assertion 1)
> value 1
> elsif (assertion 2)
> value 2
> else
> default
> 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

> So I wondered if I could get a similar looking function in ruby. Here
> is an attempt:

> class Object
> alias l lambda

> def cond(tests)
> #acts similar to scheme/LISP cond function using hash
> #key => value rather than scheme's (cond (assertion)(value)...
> (else(value)))
> tests.each_pair do |k,v|
> if k.call
> v.call
> break
> else
> next
> end
> end
> end

> def end_cond; l{true}; end
> 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 \-&gt;\{  3  &lt; 2 \} =&gt; \-&gt;\{ &#39;3 is less than 2&#39; \},
          \-&gt;\{  3  &gt; 3 \} =&gt; \-&gt;\{ &#39;3 is greater than 3&#39; \},
          \-&gt;\{ 3\+1 &gt; 4 \} =&gt; \-&gt;\{ &#39;4 is greater than 4&#39; \},
                     else: \-&gt;\{ &#39;hey, it works\!&#39; \}

> 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  &lt; 2 then &#39;3 is less than 2&#39;
     when  3  &gt; 3 then &#39;3 is greater than 3&#39;
     when 3\+1 &gt; 4 then &#39;4 is greater than 4&#39;
     else              &#39;hey, it works\!&#39;
     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

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 &lt;test&gt; then &lt;expression&gt;
when &lt;test&gt;
  &lt;expression&gt;
  &lt;expression&gt;
else
  &lt;expression&gt;
end

> for what would normally
> look like this in ruby:

> if (assertion 1)
> value 1
> elsif (assertion 2)
> value 2
> else
> default
> 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

> So I wondered if I could get a similar looking function in ruby. Here
> is an attempt:

> class Object
> alias l lambda

> def cond(tests)
> #acts similar to scheme/LISP cond function using hash
> #key => value rather than scheme's (cond (assertion)(value)...
> (else(value)))
> tests.each_pair do |k,v|
> if k.call
> v.call
> break
> else
> next
> end
> end
> end

> def end_cond; l{true}; end
> 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 \-&gt;\{  3  &lt; 2 \} =&gt; \-&gt;\{ &#39;3 is less than 2&#39; \},
          \-&gt;\{  3  &gt; 3 \} =&gt; \-&gt;\{ &#39;3 is greater than 3&#39; \},
          \-&gt;\{ 3\+1 &gt; 4 \} =&gt; \-&gt;\{ &#39;4 is greater than 4&#39; \},
                     else: \-&gt;\{ &#39;hey, it works\!&#39; \}

> 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.

But it runs fine for me in 1.8.7:

RUBY_VERSION

=> "1.8.7"

class Object
  alias l lambda

?> def cond(tests)

    #acts similar to scheme/LISP cond function using hash

?> #key => value rather than scheme's (cond (assertion)(value)...
(else(value)))**
?> tests.each_pair do |k,v|
?> if k.call

        v.call
        break
      else

?> next

      end
    end
  end

?> def end_cond; l{true}; end

end

=> nil

?> cond l{3 < 2} => l{ puts "3 is greater 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!
=> nil

What I am not entirely clear about is what's wrong with

puts case
     when  3  &lt; 2 then &#39;3 is less than 2&#39;
     when  3  &gt; 3 then &#39;3 is greater than 3&#39;
     when 3\+1 &gt; 4 then &#39;4 is greater than 4&#39;
     else              &#39;hey, it works\!&#39;
     end

That looks just fine to me.

Yes. I agree it is beter. I didn't realize that case statements could
be used with this more flexible syntax. My bad.

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.

If defined in Object class, cond could be used within almost any
context (since almost every object is an ancestor of Object).

···

On Nov 12, 6:14 am, Jörg W Mittag <JoergWMittag+R...@GoogleMail.Com> wrote:

jwm

Good Morning,

Case interrogates a single variable for its state--whether it falls in
a certain range, or is equal to such and such a value. The cond
statement is much more flexible, in that each assertion can be
completely unrelated to the other assertions--i.e. they can cover more
than the state of a single variable.

Nope, well sort of nope - you are right that it checks against a single
variable but you are missing the trick. However the default "variable" for
case is true and there are lots of options outside of the default as well.

As an example

x = 1
y = 2
case
  when x == 2 then puts 'x'
  when y == 2 then puts 'y'
end

That outputs a nice shiny "y"

or

x = 1
y = 2
case false
  when x == 2 then puts 'x'
  when y == 2 then puts 'y'
end

This outputs an even shiner "x"

And even nicer

x = 1
y = 2
case 2
  when x then puts 'x'
  when y then puts 'y'
end

A nice shiny 'y' pops up on the screen

John

···

On Thu, Nov 11, 2010 at 8:25 PM, timr <timrandg@gmail.com> wrote:

On Nov 11, 5:51 pm, Clifford Heath <n...@spam.please.net> wrote:

Oh, I see. I have always seen it in the simplest form only:
print "Enter your grade: "
grade = gets.chomp
case grade
when "A"
  puts 'Well done!'
when "B"
  puts 'Try harder!'
when "C"
  puts 'You need help!!!'
else
  puts "You just making it up!"
end

Thanks. That is certainly better.
Tim

···

On Nov 11, 8:43 pm, John W Higgins <wish...@gmail.com> wrote:

[Note: parts of this message were removed to make it a legal post.]

Good Morning,

On Thu, Nov 11, 2010 at 8:25 PM, timr <timra...@gmail.com> wrote:
> On Nov 11, 5:51 pm, Clifford Heath <n...@spam.please.net> wrote:

> Case interrogates a single variable for its state--whether it falls in
> a certain range, or is equal to such and such a value. The cond
> statement is much more flexible, in that each assertion can be
> completely unrelated to the other assertions--i.e. they can cover more
> than the state of a single variable.

Nope, well sort of nope - you are right that it checks against a single
variable but you are missing the trick. However the default "variable" for
case is true and there are lots of options outside of the default as well.

As an example

x = 1
y = 2
case
when x == 2 then puts 'x'
when y == 2 then puts 'y'
end

That outputs a nice shiny "y"

or

x = 1
y = 2
case false
when x == 2 then puts 'x'
when y == 2 then puts 'y'
end

This outputs an even shiner "x"

And even nicer

x = 1
y = 2
case 2
when x then puts 'x'
when y then puts 'y'
end

A nice shiny 'y' pops up on the screen

John