cqcallaw / newt

The newt programming language
GNU General Public License v3.0
12 stars 2 forks source link

Allow match statements to bind matches to a name #60

Closed cqcallaw closed 8 years ago

cqcallaw commented 8 years ago

As implemented, match statements bind the matched variant to a variable that has the same name as a variant. This leads to unfortunate variable shadowing when match statements are nested:

coordinate {
    cartesian {
        x:double,
        y:double
    } | polar {
        r:int,
        theta:double
    }
}

add:= (a:coordinate, b:coordinate) -> coordinate {
    match(a)
        cartesian {
            match(b)
                cartesian {
                    # `cartesian` shadows the outer matches' variable of the same name
                } | polar {
                }
        } | polar {
            match(b)
                cartesian {
                } | polar {
                    # `polar` shadows the outer matches' variable of the same name
                }
        }
}

One can work around this by assigning the outer auto-generated variable to a unique name, but it would be cleaner and more convenient to have this naming be specified as part of the match statement syntax. This specification could happen at the top level of the match, as part of the match block, or both; the best option is not yet clear. It also seems appropriate to make variable binding optional

cqcallaw commented 8 years ago

@laokaplow proposes the following syntax:

...
    match(a)
        a:cartesian {
            match(b)
                b:cartesian {
                } | b:polar {
                }
        } | a:polar {
            match(b)
                b:cartesian {
                } | b:polar {
                }
        }
...
cqcallaw commented 8 years ago

Doing the name binding near the match block seems appropriate, as it is nearest the context in which the variable would be used.

cqcallaw commented 8 years ago

Another syntax option:

...
    match(a)
        cartesian as a {
            match(b)
                cartesian as b {
                } | polar as b {
                }
        } | polar as a {
            match(b)
                cartesian as b {
                } | polar as b {
                }
        }
...
cqcallaw commented 8 years ago

It's worth noting that we cannot simply use the match expression as the name because the match expression may be the result of an operation such as function invocation instead of a simple variable evaluation. That is,

    match(f(x, y, z) + g(n))
        ...

is completely valid.