Skip to content

Instantly share code, notes, and snippets.

@seanbaxter
Last active December 3, 2021 10:01
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save seanbaxter/2e78701d6a3ea26647eec9d6045dda90 to your computer and use it in GitHub Desktop.
Save seanbaxter/2e78701d6a3ea26647eec9d6045dda90 to your computer and use it in GitHub Desktop.

Circle pattern matching

  • Retain is and as contextual keywords from P2392.
  • Combine binding and pattern in one syntax, like P1371 and Rust match.

The syntax for an inspect-clause is:

  • constraint-seq binding?

constraint-seq is a sequence of constraints:

  • is type
  • is template
  • is constraint
  • is expr
  • is [ ] - structured/designated pattern
  • is < > - alternative pattern

An as-constraint is a test and a conversion

  • as type - convert to type

There are four binding types:

  • ident - an identifier binding

  • [ binding1, constraint-seq binding?, ... ] - structured binding

  • [.name1: constraint-seq binding?, .name2: constraint-seq binding?, ... ] - designated binding

  • < constraint-seq binding? > - alternative binding.

  • Allow trailing if-guard as in rust, after the binding.

struct foo_t {
  std::string s;
  std::variant<int, double, float, const char*> v;
};

match(foo) {
  // Designated pattern. Extract members s and v.
  // s must be a string, bind to s.
  
  // v must hold a double. bind to x.
  [s: is std::string s, v: <double x>] => std::cout<< s<< ", "<< x<< "\n";
  
  // test all alternatives of v, if convertible to double, bind to x.
  // This implicitly generates a set of alternative successors, each with 
  // x declared with a different type.
  [s: is std::string s, v: <as double x>] => std::cout<< s<< ", "<< x<< "\n";

  // Bind to the active variant member of v. This causes a distinct successor
  // for each alternative type. 
  // Prints "int", "double" or "float" depending on the active member.
  // This is a generic visitor that P2392 lacks.
  [_, <x>] => std::cout<< decltype(x).string<< "\n";
}
  
match(aggregate) {
  // Destructure the first and last elements of an aggregate.
  [is std::integral is 0..10, ..., is std::floating_point is 0..M_PI f] => ...;
}

match(tuple) {
  // Check that the first and second elements are the same, and bind to x.
  [x, is x] => std::cout<< x<< "\n";

  // first element is greater than second element.
  [x, y] if x > y => std::cout<< x<< ", "<< y<< "\n";
}

// P2391R1 1.1 example that will now work on all types (except any)
match(x) {
  // Test if an int, then bind.
  is int i => std::cout<< "int "<< i;

  // Test if an integral. Don't bind here.
  is std::integral => std::cout<< "non-int integral "<< x;

  // Destructure 2-element tuple-like. Test if each element is int, then
  // bind.
  [is int a, is int b] => std::cout<< "2-int tuple "<< a<< " "<< b;

  // Destructure 2-element tuple like. Test if element 0 is 0. We don't have
  // to say "is 0" because the leading token isn't an identifier.
  // Test element 1 with the even function, then bind y.
  [is 0, is even y] => std::cout<< "point on y-axis and even y "<< y;

  // Convertible to string. Different from the first clause, which tests if
  // it's an int.
  as std::string s => std::cout<< "string "<< s;

  _                => std::cout<< "no matching value";
}

// P2392R1 3.2.2 Dereference example that will work on variants.
pair<variant<unique_ptr<Node>, Node*, double*, string>, int> v = ...;

match(v) {
  // First element is either unique_ptr<Node> or Node*.
  is [<*Node>] => ...

  // First element is dereferencable (therefore double*)
  [*_, _] => ...

  // Fist element is anything (therefore string)
  _ => ...
}

auto x = match(v1, v2) {
  // Multiply the contents of variant 1 and variant 2.
  // This generates a full NxM outer product. It's a 2D switch.
  // We can only have single return type, so construct a common
  // var type.
  <x1>, <x2> => common_var_t(x1 * x2); 
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment