From: Dmitry Vazhov on
"Set" class has meaning close to "Range" class. If we will define
Set#=== as

class Set
def ===( arg )
self.any?{|template| template === arg }
end
end

we will be able to write case/when code in haskell-like pattern-matching
style. here is an example of simple s-expression evaluator from my page:

Sexp = Set[Array, Numeric] # means - array or number
Boolean = Set[true, false]
Sexpbool = Set[Array] | Boolean # means - array or true or false


def evale(e) # function which will evaluate S-Expression
case e
when Numeric, Boolean then e
when [:-, Sexp] then - evale(e[1])
when [:-, Sexp, Sexp] then evale(e[1]) - evale(e[2])
when [:+, Sexp, Sexp] then evale(e[1]) + evale(e[2])
when [:*, Sexp, Sexp] then evale(e[1]) * evale(e[2])
when [:**, Sexp, Sexp] then evale(e[1]) ** evale(e[2])
when [:>, Sexp, Sexp] then evale(e[1]) > evale(e[2])
when [:if, Sexpbool, Sexp, Sexp] then evale(e[1]) ?evale(e[2]) :
evale(e[3])
when Object then fail("something went wrong")
end
end

def test_exp_eval
exp = [:*, [:-, 9, 2], [:+, 8, [:-, 2]]] # -> (9 - 2) * (2 + 4) = 42
assert_equal 42, evale(exp)
exp2 = [:if, true, 10, 20]
assert_equal 10, evale(exp2)
exp3 = [:if, [:>, [:**, 5, 5], 4000], 1, 2] # -> 2 , because 4000 >
5**5
assert_equal 2, evale(exp3)
end





Dmitry Vazhov wrote:
> Hello,
>
> We already have :=== operator defined in Module, Range, Regexp and Proc
> which is great for case/when statement. For all other objects :=== mean
> :==.
>
> My suggestion is to extend Array with === method:
>
> Original behaviour:
> [1,2,3] === [1,2,3] #=> true
> [1,2,3] === [1,2,4] #=> false
> [1,2,3] === 2 #=> false
>
> Adding code: -- this code is similar to Array#== , but uses :=== for
> comparing each element
> class Array
> def ===( arg )
> arg.is_a?(Array) && self.size == arg.size && (0...size).all?{|i|
> self[i] === arg[i] }
> end
> end
>
> After adding code:
> [1,2,3] === [1,2,3] #=> true
> [1,2,3] === 2 #=> false
>
> [1,2,Object] === [1,2,3] #=> true
> [1,2,/^some/] === [1,2,"some string"] #=> true
> [1,2,[Symbol, Array]] === [1,2,[:key, []]] #=> true <---- this
> is an example of deep structure matching
>
> You can see other examples at
> http://github.com/dmitryelastic/dumb-patterns-matching/blob/master/patterns_matching.rb
> and http://github.com/dmitryelastic/dumb-patterns-matching

--
Posted via http://www.ruby-forum.com/.

From: Dmitry Vazhov on
So, my question is: Do you agree that Array#=== can be useful for us?

My opinion is that it can be in ruby std library along with
Proc#===(which is already in ruby 1.9 --
http://www.aimred.com/news/developers/2008/08/14/unlocking_the_power_of_case_equality_proc/)

--
Posted via http://www.ruby-forum.com/.

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

Hi,

It doesn't look too usefull to me like that. (I mean using classes to
compare).

For this purpose I wrote something like:

# Analyse arguments given to a method(*args)
#
# Exemple:
# def m(*args)
# case args
# when ARGS[Complex]
# m(Complex.new(1,1))
# when ARGS[Integer, Boolean]
# m(2, true)
# when ARGS[[Numeric, Float], String]
# m([1, 3.14], "Hello World!")
# when ARGS[[[Integer, Integer],[Float, Rational ]]]
# m( [[1 , 2 ],[3.0 , Rational(1,2)]])
# end
# end

module Boolean; end
class FalseClass; include Boolean; end
class TrueClass; include Boolean; end

class ARGS
def initialize(*constraints)
@constraints = constraints
end

def ARGS.[](*constraints)
ARGS.new(*constraints)
end

def match?(args)
return false unless @constraints.length == args.length
@constraints.each_with_index { |constraint, i|
case constraint
when Module
unless args[i].is_a?(constraint)
return false
end
when Array
unless args[i].is_a?(Array) &&
ARGS[*constraint].match?(args[i])
return false
end
end
}
true
end

def ===(args)
match?(args)
end
end

-------

Some mails ago, I also thought Array#=== implemented a OR-related test like
in:
case 2
when -1,1,2
...
end

But that seems to be more a feature of the "block" case.

So, I think this trick can be useful in special "cases", but I don't see
enough interest to do that for the Ruby core.

Any exemples more attractive ?

2009/12/18 Dmitry Vazhov <dmitryelastic(a)gmail.com>

> So, my question is: Do you agree that Array#=== can be useful for us?
>
> My opinion is that it can be in ruby std library along with
> Proc#===(which is already in ruby 1.9 --
>
> http://www.aimred.com/news/developers/2008/08/14/unlocking_the_power_of_case_equality_proc/
> )
>
> --
> Posted via http://www.ruby-forum.com/.
>
>

From: Caleb Clausen on
> Dmitry Vazhov wrote:
>> Hello,
>>
>> We already have :=== operator defined in Module, Range, Regexp and Proc
>> which is great for case/when statement. For all other objects :=== mean
>> :==.
>>
>> My suggestion is to extend Array with === method:

I long ago did something similar, but much more extensive; I created a
large pattern-matching language/library for ruby data structures
called Reg. Instead of changing the existing Array#===, I created a
new class, Reg::Array, which has the functionality you want. A
Reg::Array can be constructed by enclosing the patterns of interest
between +[ and ].

You should have a look at Reg; you can install the gem:
gem install reg
or take a look at the github project, which contains newer (and buggier) code:
http://github.com/coatl/reg


On 12/17/09, Dmitry Vazhov <dmitryelastic(a)gmail.com> wrote:
> "Set" class has meaning close to "Range" class. If we will define
> Set#=== as
>
> class Set
> def ===( arg )
> self.any?{|template| template === arg }
> end
> end

Personally, I would rather see Set#=== be an alias for include?. The
alternation semantics that you want here are provided in Reg by
Reg::Or, which is usually created by gluing together individual
matchers that you want with the | operator. So it'd look like:
Sexp = Array|Numeric
instead of:
Sexp = Set[Array, Numeric]

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

I would absolutely love if Array recursively performed #=== on its
arguments. AFAICT Array#=== is practically identical to Array#==

On Fri, Dec 18, 2009 at 4:16 PM, Caleb Clausen <vikkous(a)gmail.com> wrote:

> > Dmitry Vazhov wrote:
> >> Hello,
> >>
> >> We already have :=== operator defined in Module, Range, Regexp and Proc
> >> which is great for case/when statement. For all other objects :=== mean
> >> :==.
> >>
> >> My suggestion is to extend Array with === method:
>
> I long ago did something similar, but much more extensive; I created a
> large pattern-matching language/library for ruby data structures
> called Reg. Instead of changing the existing Array#===, I created a
> new class, Reg::Array, which has the functionality you want. A
> Reg::Array can be constructed by enclosing the patterns of interest
> between +[ and ].
>
> You should have a look at Reg; you can install the gem:
> gem install reg
> or take a look at the github project, which contains newer (and buggier)
> code:
> http://github.com/coatl/reg
>
>
> On 12/17/09, Dmitry Vazhov <dmitryelastic(a)gmail.com> wrote:
> > "Set" class has meaning close to "Range" class. If we will define
> > Set#=== as
> >
> > class Set
> > def ===( arg )
> > self.any?{|template| template === arg }
> > end
> > end
>
> Personally, I would rather see Set#=== be an alias for include?. The
> alternation semantics that you want here are provided in Reg by
> Reg::Or, which is usually created by gluing together individual
> matchers that you want with the | operator. So it'd look like:
> Sexp = Array|Numeric
> instead of:
> Sexp = Set[Array, Numeric]
>
>


--
Tony Arcieri
Medioh! A Kudelski Brand