tc39 / proposal-pattern-matching

Pattern matching syntax for ECMAScript
https://tc39.es/proposal-pattern-matching/
MIT License
5.47k stars 89 forks source link

Multiple heads and nested lists and functions? #22

Closed 7fe closed 3 years ago

7fe commented 7 years ago

Is there a way to match multiple 1,1+ or 0+ heads(also known as variable type/instance of depending on the implementation or first value in a list)? For example let's say I have the following array of JavaScript instances where Number and String could be any type. There is the left and right side of the .. operator. The left side defines the name of the the pattern and the right is the instanceof object(with _caveats).

    [1,2,"3")] // matches [x..Number,y..Number,z..String]
    [1,2] // matches [x..Number,y..Number,z...String]
    [1,2,"3","4"] // matches [x..Number,y..Number,z...String]

In addition what about nested patterns of functions? Doing so would make JavaScript much more like a LISP.

I'm thinking something like the following in Mathematica which would return True. Remember functions in Mathematica start with are written like the following f[agrs] instead of f(args) and arrays are written like {1,2}.

MatchQ[f[1,{"List",1,2}], f[x_,{"List",y__},z___]]

If you are familiar with LISP the following is a basic example.

(setf (readtable-case *readtable*) :invert)
(load 'init.lisp)
(compile-mma)
(load-mma)
(|ReplaceAll| '(f 2 2) '(|Rule| (|Pattern| a (|BlankSequence|)) (f1 a) ) )
 > (F1 ((F1 F) (F1 2) (F1 2)))
(elt '(F1 ((F1 F) (F1 2) (F1 2))))
(|ReplaceAll| '(f 2) '(|Rule| (f (|Pattern| a (|Blank|))) (f1 a) ) )
 > (f1 a)
(|ReplaceAll| '(f a b) '(|Rule| (|Pattern| a (|Blank|))) (f 1 2) )))
> (f a b)

In Mathematica the function name you are trying to match exists before the _ while the variable name exists after the underscore. Adopting how Mathematica does it it except using the ...

f(x..,["List",y...],z...])

Basically in LISP you can match both functions and lists which are nested. Adapting more examples give me a minute.

let length = vector => match (vector) {
    { x : x.. , y : y.. , z: z.. }: Math.sqrt(x ** 2 + y ** 2 + z ** 2),
    { x: x.. , y : y.. }:   Math.sqrt(x ** 2 + y ** 2),
    [v...] :      [v].length,                   // supports 0 or more elements
    else: {
        throw new Error("Unknown vector type");
    }
}

match (arr) {
    []: /* match an empty array */,
    [x...]: /* match array of any size including 0 */,
    [x..]: /* match an array of length 1, bind its first element as x */,
    [x]: /* match an array with the first variable an actual x */,
    [x..]: /* match an array of at least length 1, bind its first element as x */,
    [ { x: 0, y: 0}, ... ]: /* match an array with the 2d origin as the first element */
}

match (val) {
    1: /* match the Number value 1 */,
    "hello": /* match the String value "hello" */,
}

match (val) {
    r..someRegExp: /* val & r matches the regexp */,
    a..Array: /* val & a is an instance of an array */,
    c..CustomType: /* val & c is an instance (or something) of CustomType */,
    p..PointInterface: /* val & p perhaps a tagged union of some sort */
}

let isVerbose = config => match (config) {
    {output: {verbose: true }}: true,
    else: false
}

values that can get reevaluated can get tricky.

let obj = {
    get x() { /* calculate many things */ }
}
match (obj.x) {
    //...
    else: obj.x // recalculates.
}

match (obj.x) {
    // ...
    x..: x // the result of evaluluating obj.x is bound as x and returned
}
littledan commented 7 years ago

I don't quite understand. What does the Mathematica code do?

littledan commented 7 years ago

What does it mean to match a function? In your JS example, what do the tildes mean?

7fe commented 7 years ago

@littledan Matching a functions is more unique to Lisp and Mathematica. I have used ... in place of the underscore in Mathematica. Here is an example in Mathematica. I'm going to try and write up some more examples.

f[a] + f[b] /. f[x_] -> x^2
a^2 + b^2`

http://reference.wolfram.com/language/tutorial/Introduction-Patterns.html.en

ljharb commented 7 years ago

How can a function be matched if not by identity? Its name and length are all you can reliably know about it.

7fe commented 7 years ago

@ljharb do you mean how can they be matched internally or what would the syntax be?

ljharb commented 7 years ago

Internally. There's no other meaningful information available (anything that's newly matchable constitutes new exposure of information about a function, and that could violate security concerns)

7fe commented 7 years ago

@ljharb if you do function.toString() you often get the entire functions body depending on the implementation. This is just one step further along you to pattern match such.

ljharb commented 7 years ago

Correct, but that's not something that we should be matching on.

7fe commented 7 years ago

@ljharb Pattern matching truly becomes useful when the language is more like LISP which I guess is my opinion.

bterlson commented 7 years ago

I don't see how we can support pattern matching on functions. We'd need a proposal for multi-methods or similar which is out of scope for this proposal (but should be considered).

I still don't understand what "heads" means above?

7fe commented 7 years ago

@bterlson If we are ignoring matching pattern matching functions then Heads can bascically be regarded as the variables instanceof value(with caveats). In haskell it is the first value of a list but that isn't particularly useful and would be covered easily by the implementation above like so [first..,rest...]

dustbort commented 3 years ago

May I ask why this was reopened after 3 years? Honestly, I reread OP several times and I don't understand the issue. Are you essentially asking for active patterns? If so, active patterns don't make sense without tagged union types. If you are asking about pattern matching, there is already this issue.