Toying around with an approach to pattern matching

105 views
Skip to first unread message

John Evans

unread,
Apr 17, 2012, 2:40:00 PM4/17/12
to General Dart Discussion
Some info:
http://phylotic.blogspot.com/2012/04/proposed-pattern-matching-syntax-for.html

Branch:
https://github.com/prujohn/dart/tree/pattern_matching

I'm taking the same approach I saw with the await keyword
implementation, which is to define separate entry point, and thereby
isolate any work on this as much as possible.

The 'match' keyword and it's construct would basically transform to a
IF/ELSE IF/ELSE chain before compilation to js.

Certainly open to any thoughts/suggestions.

Don

unread,
Apr 17, 2012, 5:19:37 PM4/17/12
to General Dart Discussion
Could someone describe some scenarios where this would be useful? I
don't mean to sound arrogant, but I really don't understand why this
is needed. I'm pretty wary of more statements in general, but
especially ones that seem to promote switch like control flow where
good OO design is what's really needed.

On Apr 17, 2:40 pm, John Evans <pruj...@gmail.com> wrote:
> Some info:http://phylotic.blogspot.com/2012/04/proposed-pattern-matching-syntax...

John Evans

unread,
Apr 17, 2012, 6:21:17 PM4/17/12
to General Dart Discussion
@Don: I've found pattern matching constructs to be quite useful in
more functional languages like Haskell and F#. This is really just an
experiment to see how it might work in Dart.

On face value, I find it to be more concise and readable than a long
chain of IF ... ELSE IF... ELSE

For example, take lines #260 - #397 in
https://github.com/dart-lang/dart/blob/bleeding_edge/frog/tokenizer.g.dart
of the current frog implementation. I think there's a case where
pattern matching would come in very handy in place of the trees of IF
statements.

The keyword to remember with all this is: experiment.

Sam McCall

unread,
Apr 17, 2012, 7:37:28 PM4/17/12
to John Evans, General Dart Discussion

I think you can get this feature with less language additions...

interface Matcher {
  bool matches(object);
  Matcher.any() {
    // return a matcher that matches anything
  }
  Matcher.not(matcher) {
    // etc
  }
}
bool match(pattern, object) {
  return (pattern is Matcher)
    ? pattern.matches(object)
    : pattern == object;
}
class List<T> implements Matcher {
  bool match(obj) {
    if (obj is! List || obj.length != length) return false;
    for (var i=0; i<length; i++) {
      if (!matches(this[i], object[i])) return false;
    }
    return true;
  }
}

Now allow a 'match' clause in a switch statement. Like 'case' but evaluates matches(matchPattern, switchValue).

Now you can write:
switch([a, b, c]) {
  match [true, 42, "x"]:
    return 1;
  match [true, Matcher.not(42), Matcher.any()]:
    return 2;
  default:
    return 3;
}

Not to mention having Regex, Range, and Function implement Matcher...

(Hope this is clear, on phone...)

John Evans

unread,
Apr 17, 2012, 8:06:46 PM4/17/12
to General Dart Discussion
I really like your approach Sam. Believe me when I say I am in full
support of keeping language additions to a minimum.

I wonder how your approach would work in light of today's public
announcement regarding intention to restrict switch to compile-time
constant int/String?
http://news.dartlang.org/2012/04/dart-language-progress-update.html
> On Apr 18, 2012 12:21 AM, "John Evans" <pruj...@gmail.com> wrote:
>
>
>
>
>
>
>
> > @Don: I've found pattern matching constructs to be quite useful in
> > more functional languages like Haskell and F#.  This is really just an
> > experiment to see how it might work in Dart.
>
> > On face value, I find it to be more concise and readable than a long
> > chain of IF ... ELSE IF... ELSE
>
> > For example, take lines #260 - #397 in
> >https://github.com/dart-lang/dart/blob/bleeding_edge/frog/tokenizer.g...

Sam McCall

unread,
Apr 17, 2012, 8:46:47 PM4/17/12
to John Evans, General Dart Discussion

I'm really not sure. (I'm not on the dart team btw, just an interested observer).
I think having special 'low-level switch' syntax and no 'high-level switch' would be unfortunate in a language like Dart, I'd like the reverse.

You could still fake one with a pure library...

Match
  .when([true, 42, "x"], (){ ... })
  .when(...)
  .evaluate([a,b,c]);

But it's harder to read, you're limited by non-local returns, etc.

Ladislav Thon

unread,
Apr 18, 2012, 2:46:34 AM4/18/12
to John Evans, General Dart Discussion
I wonder how your approach would work in light of today's public
announcement regarding intention to restrict switch to compile-time
constant int/String?
http://news.dartlang.org/2012/04/dart-language-progress-update.html

I might be hijacking the thread, but still... I sincerely hate switch statement in C languages family. This might qualify as "over-innovation", but one of my dreams for Dart is getting rid of the switch statement completely and replacing it with pattern matching. I know that pattern matching (and switch too) is kinda anti-OO, but Dart isn't purely OO language and functional approach makes sense in a lot of situations. One could argue that it's perfectly possible to have a switch keyword for the match operation, but that might create unsatisfied expectations.

On the other hand, limiting the switch statement to compile-time constant ints/Strings/possibly enums makes sense to me, because I almost never use switch anyway, and it's a great opportunity to optimize certain special situations. So: limited switch + unlimited match is the way to go! :-)

LT

Kasper Lund

unread,
Apr 18, 2012, 3:31:08 AM4/18/12
to John Evans, General Dart Discussion
Hi John,

I just wanted to point out that most of the work we're doing on our
Dart-to-JavaScript compiler happens in lib/compiler, where our new
compiler is shaping up to be a replacement for frog. We still have
more work to do -- in particular on the size of the generated code --
but we are planning on making dart2js (which is based on the
lib/compiler code) available in the SDK pretty soon so people can
start experimenting with it.

Cheers,
Kasper

Lars Tackmann

unread,
Apr 18, 2012, 4:51:09 AM4/18/12
to General Dart Discussion


On Apr 17, 8:40 pm, John Evans <pruj...@gmail.com> wrote:
> Some info:http://phylotic.blogspot.com/2012/04/proposed-pattern-matching-syntax...
>
> Branch:https://github.com/prujohn/dart/tree/pattern_matching
>
> I'm taking the same approach I saw with the await keyword
> implementation, which is to define separate entry point, and thereby
> isolate any work on this as much as possible.
>
> The 'match' keyword and it's construct would basically transform to a
> IF/ELSE IF/ELSE chain before compilation to js.
>
> Certainly open to any thoughts/suggestions.

+1000

The only thing I really miss in dart is F#/SML style pattern matching.
I have tons of statements like this

----
var expr;
:
if(expr is SpecificExpr) {
// editor does not handle expr as SpecificExpr unless one does
SpecificExpr s = expr;
:
} else if(expr is OtherExpr) {
// same issue as above
:
}
----

it would be really nice to be able to write

----
expr match {
case SpecificExpr => {
// in this block the dart editor could auto complete expr as type
SpecificExpr
:
}
case OtherExpr => {
:
}
case _ => throw "unhandled expr $expr";
}
----

At the very least some kind of C# like "as" keyword would be nice

----
SpecificExpr e = expr as SpecificExpr
if(e!==null) {
:
}
----

although this type of code is not as clean as the pattern matching
solution above.


--
Lars Tackmann

Don

unread,
Apr 18, 2012, 8:52:11 AM4/18/12
to General Dart Discussion
Taking all this into account, perhaps it would be better to just have
pattern matching to handle these scenarios and just getting rid of
switch. I just hope we don't go with all of the above...

Lasse R.H. Nielsen

unread,
Apr 18, 2012, 10:10:48 AM4/18/12
to Lars Tackmann, General Dart Discussion
On Wed, Apr 18, 2012 at 10:51, Lars Tackmann <ltac...@gmail.com> wrote:
> it would be really nice to be able to write
>
> ----
> expr match {
>  case SpecificExpr => {
>    // in this block the dart editor could auto complete expr as type
> SpecificExpr
>    :
>  }

Matching without binding is a lost opportunity.
A successful match tells you something - the type of a value, the
structure of a datatype, etc.
Something should carry that information into the following code.

In your example above, you want expr to carry the match information
itself, but if expr is a large
expression, it probably won't be repeated anyway.
If instead it was:
case Pattern x => ...
then x would carry the value of expr *and* the information that it
matched the Pattern.

Same with the type checks. They are separated from their consequences:
if (expr is Type)
doesn't capture the success of the match. If instead it was
typecase expr { case Type x: ... }
then the identifier x would carry the type.

Said differently: A test should not (always) be just an expression
that results in a binary value, it should be the guardian of a scope
where the test is known to be true (or false), and the consequences of
the test should be available in the scope, e.g., as a correctly typed
variable.

It's probably the functional influence that makes me think like that -
bindings are cheap when they are immutable.
/L
--
Lasse R.H. Nielsen
l...@google.com
'Faith without judgement merely degrades the spirit divine'
Google Denmark ApS - Frederiksborggade 20B, 1 sal - 1360 København K -
Denmark - CVR nr. 28 86 69 84

Paul Brauner

unread,
Apr 18, 2012, 10:37:35 AM4/18/12
to Lasse R.H. Nielsen, Lars Tackmann, General Dart Discussion
On Wed, Apr 18, 2012 at 16:10, Lasse R.H. Nielsen <l...@chromium.org> wrote:
On Wed, Apr 18, 2012 at 10:51, Lars Tackmann <ltac...@gmail.com> wrote:
> it would be really nice to be able to write
>
> ----
> expr match {
>  case SpecificExpr => {
>    // in this block the dart editor could auto complete expr as type
> SpecificExpr
>    :
>  }

Matching without binding is a lost opportunity.

+1. Matching is about destructuring AND binding. One way of simulating that is by means of visitors. The other way I know is pattern combinators (http://www.itu.dk/people/mir/typesafepatterns.pdf). In both cases, I don't think it can been advertised as being the canonical way of doing pattern matching in Dart: there's too much boilerplate or conventions.

Paul
Reply all
Reply to author
Forward
0 new messages