Abstract This document describes AsmL, a specification language based on abstract state machines. Foundations of Software Engineering Microsoft Research (c) Microsoft Corporation. All rights reserved. Contents 1 Introduction 6



Download 0.93 Mb.
Page9/25
Date28.01.2017
Size0.93 Mb.
#9776
1   ...   5   6   7   8   9   10   11   12   ...   25

1.27Patterns


pat ::= "_"
| literal
| id [ as typeExp
| tuplePat
| datatypePat
| mapletPat

tuplePat ::= "(" pats ")"
datatypePat
::= typeName [ "(" [ pats ] ")" ]
mapletPat
::= pat "->" pat
pats
::= pat { "," pat }

Patterns are destructuring forms. With patterns, the user can decompose a value into its constituent parts using syntax that mirrors the value's constructor (see section 1.24).

Patterns are used for matching, the process of testing whether the constructor of a given value has the same form as a given pattern. Matching occurs when the pattern form is consistent with the constructor of the value being matched.

Pattern syntax is also used for binding, the process of associating an identifier with a value. (The "let" statement is an example of binding.) Note that matching must also occur if any binding is to take place.

Patterns occur in four contexts in AsmL:



  • As cases in a match statement (see section below).

  • In a let statement to indicate the names that will be bound to values (see section below).

  • In binder clause to give the names that will take on multiple, iterated values (see below).

  • Within another pattern, to form a nested pattern.

  1. Symmetry of construction and pattern matching

structure Point

x as Integer

y as Integer
Main()

let p = Point(3, 2) // constructor

let Point(a, b) = p // pattern

WriteLine(a) // prints 3


Note in the example how the constructor Point(3, 2) has the same form as the pattern Point(a, b). The constructor yields a value, while the pattern is matched against an existing value to bind a = 3 and b = 2.

1.27.1Universal patterns


The universal pattern is an underscore token (“_”). The universal pattern can be matched against any value but does not result in a new binding of a name to a value.

Note that the underscore token has special meaning and may be used in AsmL only for the universal pattern.


1.27.2Literal patterns


A literal pattern has the same form a literal (such as a string literal or a numeric literal). A match occurs if the value being tested equals the literal given. No binding results.

  1. Pattern matching without binding

CheckRemainder(i as Integer, r as Integer)

match i mod r

0: WriteLine(“Divides evenly!”)

1: WriteLine(“Has one left over”)

_: WriteLine(“Has more than one left over”)
Main()
CheckRemainder(3, 2) // prints "Has one left over"
In Example 15 the value of expression i mod r matches the pattern 1 (since in this example i mod r means 3 mod 2, or the value 1.)

1.27.3Identifier patterns


An identifier pattern matches any value, and a binding is established between the name and the matched value. Its syntax is just that of an identifier.

  1. Single-name patterns

Main()

let x = (1, “first”)


choose y in {1, 2}

WriteLine({z | z in {0..y}}) // prints {0, 1} or {0, 1, 2}


In Example 16 x, y and z are identifier patterns.

1.27.4The type pattern


A type pattern has the form id as type. It is similar to the identifier pattern, but the type pattern only succeeds if the value being matched is a subtype of type. If a match occurs, the value is bound to the name id with declared type type.

  1. Type patterns

structure Point

x as Integer

y as Integer
structure ColorPoint extends Point

color as String


PrintPointColor(p as Point)

match p


cp as ColorPoint:

WriteLine(cp.color)

_:

WriteLine("No color present")


Main()

a = ColorPoint(1, 2, "red")

PrintPointColor(a) // prints "red"
The form cp as ColorPoint in Example 17 is a type pattern. This example shows a type-safe way of "downcasting," or determining at runtime whether a value is in the domain a type other than its declared type.

1.27.5Tuple pattern


The form (pattern, pattern ...) is called the tuple pattern. The pattern matches if its form is the same as the construction expression of the given value and each of its patterns match pairwise with those of the value. It is possible that pattern matching is recursive.

  1. Tuple pattern

Main()

let a = (1, (2, "abc"))

let (b, (_, c)) = a // b is 1, c is "abc"

WriteLine(c) // prints "abc"



1.27.6Datatype pattern


A datatype pattern has the form typeName (pattern1, pattern2, …). The pattern matches if the name and patterns match the default construction expression of the given value. This is similar in form to the default construction expression of that datatype, either class, structure or enum.

If the constructor of a structure or class does not have any parameters, then the pattern corresponding to that constructor may omit the parentheses. The patterns for enums do not include parentheses.

Note that, unlike the class constructor, the datatype pattern does not use the keyword new. (This is an exception to the rule stated above that patterns have the same syntax as constructors.)


  1. Destructing patterns for structures

structure List of T

case Nil


case Cons

head as T

tail as List of T
Main()

let x = Cons of Integer(2, Nil of Integer)

let Cons of Integer(a, _) = x // same as a = 2

let y = Cons(10, x)


match y

Cons of Integer(10, Cons of Integer(2, _)):

WriteLine("Matched y with nested pattern")
Note to users

Pattern matching should not be used for datatypes that inherit fields from a supertype. (The behavior in this case is undefined and may change in future versions of AsmL.)

1.27.7The maplet pattern


A maplet pattern has the form pattern1 -> pattern2. The symbol "->" is read as "maps to".

The context in which a maplet pattern may appear is more restricted than other kinds of patterns. A maplet pattern may only appear within a binder form (see below), before the keyword in. A maplet pattern may not be used within a match case statement, within a let binding or nested within another pattern. The only use of a maplet pattern is to produce bindings for key/value associations given in a map.

The maplet pattern in the form pat1 -> pat2 in exp produces bindings for every case where pat1 matches a key value of the map given by exp and pat2 matches the lookup value associated with that key.


  1. Maplet patterns

const myMap = {"one" -> 1, "two" -> 2, "three" -> 3}
IsOdd(x as Integer) as Boolean

return (1 = x mod 2)


Main()

step


let oddNumbers = {i | i -> j in myMap where IsOdd(j)}

WriteLine(oddNumbers) // prints {"one", "three"}

step

let two = the i | i -> 2 in myMap



WriteLine(two) // prints "two"
In Example 20 the forms i -> j and i -> 2 are maplet patterns. OddNumbers is the set of all i such that the key/value pair i-mapsto-j is found in the table myMap and j is an odd number. Two is the (unique) i such that i-mapsto-2 is found in the table myMap.

Note to users

Maplet patterns are more restricted than other patterns. This arises from the fact that there is no value corresponding to key/value associations that constitute a map.


Download 0.93 Mb.

Share with your friends:
1   ...   5   6   7   8   9   10   11   12   ...   25




The database is protected by copyright ©ininet.org 2024
send message

    Main page