Hacker News new | ask | show | jobs
Show HN: Switch statement + lambdas = pattern matching in DeltaScript (gist.github.com)
1 points by flinkerflitzer 646 days ago
DeltaScript is a skeletal scripting language that can be easily extended with types and function bindings. These extensions then constitute dialects, and are effectively DSLs in their own right.

I have been developing DeltaScript for the scriptable pixel art editor that I am working on, but I have plans to reuse it for other projects with entirely separate scopes in the future.

I have implemented DeltaScript as an interpreter that targets Java. However, DeltaScript is technically target-agnostic, and could be implemented as a compiled or interpreted language. I haven't gotten round to documenting or specifying the language yet, but the syntax grammar and implementation are both available.

DeltaScript's syntax is C-like, and most of the keywords and syntactical conventions I opted for fall firmly within that family. However, I wanted to do something more unique with my version of switch statements.

Switch statements have a *control expression*. That is the expression whose value is checked against in the statement's cases. Rather than simply comparing the control to possible values, I wanted to be able to pattern match the control expression. So, I devised the `when` statement, which has two separate types of non-trivial cases: `is` and `passes`.

`is` is a conventional switch case, which provides an expression pf the same type as the control expression to compare it to. If the values are equal (`==`) as defined by the type, the body of the `is` case is executed.

`passes`, on the other hand, provides a test. For a control expression of type `T`, passes provides a function of type `(T -> bool)`; that is, a function that takes a single parameter of type `T` and returns a truth value. The control expression is passed into the test, and the body of the `passes` case is executed if and only if the test returns `true`.

The test can be provided as a direct function pointer, a variable storing a function, or a lambda expression.

Let me know what you think!

1 comments

I'm waiting for pattern matching to be added to JS. The proposal[1] documents a lot of thought on how to add pattern matching to a language, including prior art in other languages. (Pattern matching was introduced to me via either F# or Erlang/Elixir.)

DeltaScript pattern matching seems to be missing two major features; perhaps intentional because the implementation is more difficult:

1. Binding - useful to be able to assign variables to sub-parts of the control value.

2. Structural matching - matching based on the shape of the control value.

I suppose both binding and structural matching can be accomplished with more verbose `passes` tests. (Also some redundant code to get the bindings; perhaps the `passes` test could return optional bindings.)

[1]: https://github.com/tc39/proposal-pattern-matching

That's an interesting observation. Thanks for taking the time to think critically about my implementation. I posted about this on Reddit and someone pointed out something similar.

I'll link that post for reference: https://www.reddit.com/r/ProgrammingLanguages/comments/1fb5y...

The gist (hehe) was that a full lambda expression in a `passes` case could often feel like overkill. This was the possible solution I suggested:

    What I could do is similar to what you suggested in another comment and similar to what C# does, where I add a third type of case that implicitly substitutes the control expression into a longer expression. Something like this, tentatively using the keyword `matches`:

    int x = rand(0, 11);
    
    when (x + 2) {
        matches _ < 5 || _ > 9 -> { /* body */ }
    }
Here is a structural matching example:

    orientation(image img -> string) {
        when (img) {
            matches _.width == _.height -> return "square";
            matches _.width > _.height -> return "landscape";
            otherwise -> return "portrait";
        }
    }