module Match { 
 
  // MATCH AND PATTERN BASICS 
 
  // match is a conditional where the conditions are expressed as 
  // a set of patterns.  patterns look like regular values but 
  // can also include placeholders, wildcards, and variables 
  // that capture values as part of matching process.   
  // 
  // multiple patterns can be specified for a given condition,  
  // and an optional if clause can be added to provide an 
  // additional constraint on the match via a boolean expression. 
 
  // The full form of a match is: 
  // 
  //  match (expression) { 
  //    pattern if condition => block;   // repeats 
  // } 
  // 
 
  // MATCHING VALUES 
 
  fn test1() { 
 
    let x : int = 1; 
    let y = 3; 
 
    // patterns can be specific constant values, or references 
    // to variables or constants.  use _ to match any value 
    // use | to specify multiple patterns to match. 
    match (x) { 
      1 | 2 | y  => print("one or two or y"); 
      _          => print("something else"); 
    } 
  } 
 
  // MATCHING TYPES 
 
  fn test2() { 
 
    let x : int | string | bool = 1; 
 
    // use types as patterns to match on the type of the expression 
    match (x) { 
      string  => print("string"); 
      int     => print("int"); 
      bool    => print("bool"); 
    } 
  } 
 
  // CAPTURING VARIABLES 
 
  fn test3() { 
 
    // use @x : pattern to match a pattern and capture the value 
    // into variable x. the captured variable is scoped to the  
    // code after the =>. 
 
    let x : int | string | bool = 1; 
 
    // match based on type and capture the typed value 
    match (x) { 
      @a : string   => print(a);     // a is string 
      @a : int      => print(a);     // a is int 
      @a : bool     => print(a);     // a is bool 
    } 
  } 
 
  // MATCHING STRUCTS 
 
  struct Velocity { 
    dx: int; 
    dy: int; 
  } 
 
  fn test4() { 
    let v = Velocity(0, 1); 
     
    // use a struct pattern to match a struct. 
    // using _ for a field value or omitting the  
    // field matches all values in that field. 
    match (v) { 
      Velocity(0, 0)      => print("stationary"); 
      Velocity(dx: 0)     => print("moving vertically"); 
      Velocity(dy: 0)     => print("moving horizontally"); 
      _                   => print("moving diagnonally"); 
    } 
  } 
 
  // MATCHING MAPS 
 
  fn test5() { 
    let m = {"a" : true, "b" : false}; 
 
    // use a map pattern to specify the value to match. 
    // omitting a key means it will be matched. 
    match (m) { 
      {"a" : @a}            => print("a is ${a}"); 
      {"a" : _, "c" : _}    => print("has a and c keys"); 
    } 
 
  } 
 
  // MATCHING ARRAYS 
 
  fn test6() { 
    let a = [1, true, false]; 
 
    // use an array pattern to specify what to match. 
    // use _ to match any value in a position. 
    // and use ... to match the rest of the array. 
    match (a) { 
      [123, ...]          => print("starts with 123"); 
      [true, true, _]     => print("array size 3 with first two values true"); 
      [@a, @b, ...]       => print("first two values are ${a}, ${b}"); 
    } 
  } 
 
  // MATCH WITH IF 
 
  fn test7() { 
    let v = Velocity(5, 10); 
 
    // add if followed by a boolean expression the pattern 
    // to provide additional constraints on the match. 
    match (v) { 
      Velocity(dx : @dx, dy : @dy) if dx > 7 || dy > 7  => print("moving quickly"); 
      Velocity(dx : @dx, dy : @dy) if dx < 3 || dy < 3  => print("moving slowly"); 
      _                                                 => print("moving average"); 
    } 
  } 
 
  // MATCH AS AN EXPRESSION 
 
  fn test8() { 
    let tshirt = 1; 
 
    // match evaluates to the value of the matching expression. 
    let s = match (tshirt) {    
      1 | 2           => "small";   // this pattern matches, so s is set to "small" 
      3 | 4 | 5       => "medium"; 
      _               => "large"; 
    } 
  } 
}