"Yukihiro Matsumoto" <matz / ruby-lang.org> wrote
> |Semantics of Multiple Values
>
> Interesting, but I'm afraid this one is too big (and too complex)
> change.  I'd like to see a language with this semantics though.

Unification as 2-way pattern matching seems belong outside this proposal.

But perhaps Multiple Values could fit consistently into a more general
framework of one-way pattern matching for variable binding/assignment. It
seems duck typing also fits into such a pattern matching framework.

Here are a couple of usages examples of pattern match:

## call with multiple values
    def f (x, y, z=nil); end
    def g; return 1, 2; end
    x,y = g() #x=1, y=2
    f(g()) # same as f(1,2,nil)
    f(g(),3) # same as f(1,2,3)

## conditional multiple assignment
    {p: x, q: y} ||= h
    # match x if x is not nil, then x = h[:p]
    # match y if y is not nil, then y = h[:q]
    # overall match never fails


## method call with pattern-matched arg list
  class C
    def f ( a1, [a2,a3], {p: a4}, a5.(q: a6, r: a7, s:) ) ; end
  end
  C.new.f (w, x, y, z)
  # object match for method 'f'
    # multiple values match formal args with w,x,y,z
        # assuming w,x,y,z are not 'multiple values'
        # variable match: a1 = w
        # array match: a2, a3 = x[0],x[1]
        # hash match: a4 = y[:p]
        # object match: respond_to? :q,:r,:s
        #   a5 = a; a6 = z.q;  a7 = z.r

Why?
  - Makes intent and usage clear
  - Duck typing: patterns are duck types .(q:, r:, s:)

So here is my attempt at defining Pattern:

Pattern
-------
A Pattern is a syntactic form containing 0 or more variables. It can be used
in place of a variable, anywhere that variable could be initialized or
assigned (lvalue?). The Pattern is matched at run-time (to the extent
necessary), resulting in either
- successful match + variable bindings + success action
- failed pattern match + failure action

A pattern, to match and bind, walks the target structure:
- by position (array, positional args, multiple values, regex)
- by name (hash, keyword args, object accessors/methods)
- by magic (&block args, others?)

Kinds of patterns + pattern match:

- variable + variable assigment
    x                x = a
    # always matches

- multiple values + multiple assigment
    x,y,z
                    x,y,z = a, b, c
                    x,y,z = a, b # a, b, nil
                    x,y,z = a # a, nil, nil
    def f(p); return 1, 2; end
                    x,y,z = f(a) #1,2,nil
                    x,y,z = f(a), b #1,2,b
    *v = 1,2
                    x,y,z = *v, 3 #1, 2, 3
    # multiple values is a separate type
    # "," extends multiple values, like Array#concat
    # rhs treated as multiple values (extended by nil's)
    # always matches on assigment
    # can fail on method invocation (below)

- *arg vary-ary variable
    *x                *x = 1, 2, 3
    # always matches, assigns an array
    # *x also converts back to multiple values

- method definition + method invocation
    X#f(p,q)           x.f(a,b)
    X#f(p: 10)        x.f(p: a)
    X#f(p, *q)       x.f(a, b, c)
    # fail with exception if parameter mismatch
    # else invoke method

- hash pattern + pattern assigment
    {p: x}          {p: x} = a
    # fail with exception if !a.is_a? Hash
    # else x = a[:p]

- array pattern + pattern assigment
    [x, y, z]       [x, y, z] = [a, b, c]
    # fail if !rhs.is_a? Array
    # else assign rhs[0], rhs[1], ...
    # like hash pattern: [1: x, 2: y, 3: z]

- object pattern + pattern assigment
    .(p: x, q: y)
    .(p: x, q: y) = a
    # match if a.respond_to? :p, :q
    # assign x = a.p;  y = a.q
    o.(p:x, q:y) = a
    # assign o = a; x=a.p; y=a.q
    o.(p,q)
    # match if a.respond_to? :p, :q
    # perhaps extend to match specified classes?

- conditional assigment
    x ||= value
    # match if x was nil; no-op if fail
    # Think of pattern: x||

- regex pattern + regex match
    /abc*/            /abc*/ =~ string
    # perhaps '=' would work for '=~'

Any checking required to bind variables must take place at (by) run-time.
Some checks that define pattern match, but do not bind variables, may be
optionally turned off.

The behavior of success and failure depend on the context in which the
pattern appears. e.g. method invocation x.f(a) will pattern match x's
pattern of methods x.<m> with "x.f(a)". Success means the method is invoked.
Failure means either undefined method, or wrong number of arguments, or
missing 2.0 keyword argument, or missing block, etc. depending on what
failed.

Thoughts? Full of holes?

(btw: Beta pushed this whole pattern/match about as far as it can go).