Repository: asteroid-lang/asteroid (language: python)

Issue:
preserving declarative nature of first-class pattern matches
The replaces/supersedes issue #50.  One of the strength of pattern matching is its declarative nature -- "you get what you see".  Unfortunately this gets lost when working naively with first-class patterns,
```
let Pair = pattern (x,y).

let *Pair = (1,2).  -- hidden bindings of the variables x and y
assert( x == 1).
assert(y == 2).
```
Here the pattern match of the first class pattern `*Pair` to the value `(1,2)` introduces the bindings x&rarr;1 and y&rarr;2 into the local scope.  The problem is that these bindings are completely hidden from the user reading the program text and thus destroying the declarative nature of pattern matching.

We highly recommend that first-class patterns are always expressed as *constraint patterns* that do not introduce bindings into the current scope.   However, bindings are an important part of pattern matching so in order to recover a more declarative way to reintroduce the bindings into the local scope we support the `bind` keyword.  Here is the example written with a constraint pattern,
```
let Pair = pattern %[(x,y)]%.

let *Pair = (1,2).  -- bindings of the variables x and y are not available
assert( x == 1).  -- fails
assert(y == 2).  -- fails
```
by using the keyword `bind` in conjunction with a constraint pattern we can make those bindings explicit,
```
let Pair = pattern %[(x,y)]%.

let *Pair bind [x, y] = (1,2).  -- bindings of the variables x and y are now visible again
assert( x == 1).
assert(y == 2).
```
We can also rename bindings on-the-fly in order to prevent name clashes in the current scope.  Consider,
```
let Pair = pattern %[(x,y)]%.

function add with ( *Pair bind [x as a, y as b], 
                                 *Pair bind [x as c, y as d] ) do
   return (a+c, b+d).
end 
```
The `bind` keyword can only be applied to constraint patterns.  It would be an error to apply it to any kind of other pattern.


Discussion / hints:

Fix patch:
diff --git a/asteroid/frontend.py b/asteroid/frontend.py
index 17a53c00..4d97d033 100644
--- a/asteroid/frontend.py
+++ b/asteroid/frontend.py
@@ -585,7 +585,7 @@ def pattern(self):
             self.lexer.match('LCONSTRAINT')
             v = self.exp()
             self.lexer.match('RCONSTRAINT')
-            return ('constraint', v)
+            return ('constraint', v, ('nil',))
         else:
             v = self.head_tail()
             return v
@@ -804,7 +804,7 @@ def call_or_index(self):
     #    | FALSE
     #    | NONE
     #    | ID
-    #    | '*' call_or_index /* pattern dereferencing */
+    #    | '*' call_or_index binding_list? /* pattern dereferencing */
     #    | NOT call_or_index
     #    | MINUS call_or_index
     #    | PLUS call_or_index
@@ -850,7 +850,11 @@ def primary(self):
         elif tt == 'TIMES':
             self.lexer.match('TIMES')
             v = self.call_or_index()
-            return ('deref', v)
+            if self.lexer.peek().type == 'BIND': # binding list
+                l = self.binding_list()
+            else:
+                l = ('nil',)
+            return ('deref', v, l)
 
         elif tt == 'NOT':
             self.lexer.match('NOT')
@@ -917,6 +921,37 @@ def primary(self):
             #raise SyntaxError("syntax error at '{}'"
                 # .format(self.lexer.peek().value))
 
+    ###########################################################################################
+    # binding_list
+    #   : BIND '[' binding_term (',' binding_term)* ']'
+    def binding_list(self):
+        dbg_print("parsing BINDING_LIST")
+        self.lexer.match('BIND')
+        self.lexer.match('LBRACKET')
+        bl = [ self.binding_term() ]
+        while self.lexer.peek().type == 'COMMA':
+            self.lexer.match('COMMA')
+            bl.append(self.binding_term())
+        self.lexer.match('RBRACKET')
+        return ('binding-list', bl)
+
+    ###########################################################################################
+    # binding_term
+    #   : ID (AS ID)?
+    def binding_term(self):
+        dbg_print("parsing BINDING_TERM")
+        name_tok = self.lexer.match('ID')
+        if self.lexer.peek().type == 'AS':
+            self.lexer.match('AS')
+            as_name_tok = self.lexer.match('ID')
+            return ('binding-term', 
+                    ('id', name_tok.value), 
+                    ('id', as_name_tok.value))
+        else:
+            return ('binding-term', 
+                    ('id', name_tok.value), 
+                    ('id', name_tok.value))
+            
     ###########################################################################################
     # tuple_stuff
     #   : exp (',' exp?)*
diff --git a/asteroid/grammar.txt b/asteroid/grammar.txt
index be99e6ae..3dd4e791 100644
--- a/asteroid/grammar.txt
+++ b/asteroid/grammar.txt
@@ -9,7 +9,7 @@
  - Use C++ style comments for any comments that you DO want to be displayed
    in the target documentation.
  - C style comments for any comments that you DO NOT want to be displayed
-   in the target documentation.
+   in the target documentation -- like the one you are reading right now...
  **************************************************************************************/
   ////////////////////////////////////////////////////////////////////////////////////////
   // statements
@@ -126,7 +126,7 @@
     | FALSE
     | NONE
     | ID
-    | '*' call_or_index   /* pattern dereferencing */
+    | '*' call_or_index  binding_list? /* pattern dereferencing */
     | NOT call_or_index
     | MINUS call_or_index
     | PLUS call_or_index
@@ -137,6 +137,14 @@
     | function_const
     | TYPEMATCH           // TYPEMATCH == '%'<typename>
 
+// Note: binding lists are only supported for constraint patterns
+
+  binding_list
+    : BIND '[' binding_term (',' binding_term)* ']'
+
+  binding_term
+    : ID (AS ID)?
+
   tuple_stuff
     : exp (',' exp?)*
     | empty
diff --git a/asteroid/lex.py b/asteroid/lex.py
index 95323399..a6506d14 100644
--- a/asteroid/lex.py
+++ b/asteroid/lex.py
@@ -1,7 +1,7 @@
 ###########################################################################################
 # Lexer for Asteroid
 #
-# (c) Lutz Hamel, University of Rhode Island
+# (c) University of Rhode Island
 ###########################################################################################
 
 import re
@@ -13,7 +13,9 @@
 keywords = {
 #   value:          type:
     'and'           : 'AND',
+    'as'            : 'AS',
     'assert'        : 'ASSERT',
+    'bind'          : 'BIND',
     'break'         : 'BREAK',
     'catch'         : 'CATCH',
     'data'          : 'DATA',
diff --git a/asteroid/support.py b/asteroid/support.py
index 31853916..7460162b 100644
--- a/asteroid/support.py
+++ b/asteroid/support.py
@@ -341,14 +341,18 @@ def term2string(term):
         return term_string
 
     elif TYPE == 'constraint':          # Handle a constraint-only pattern
-        (CONSTRAINT,ptrn) = term
+        (CONSTRAINT,ptrn,bl) = term
+        if bl[0] != 'nil':
+            raise ValueError("term2string: binding term lists not supported")
         term_string = '%['
         term_string += term2string(ptrn)
         term_string += ']%'
         return term_string
 
     elif TYPE == 'deref':               # Handle a first-class pattern
-        (DEREF, d_exp) = term
+        (DEREF, d_exp, binding_list) = term
+        if binding_list[0] != 'nil':
+            raise ValueError("internal error: binding lists in term2string not supported")
         term_string = "*" + term2string(d_exp)
 
         #Get the actual pattern from the symbol table
diff --git a/asteroid/walk.py b/asteroid/walk.py
index d414dbda..83926fd2 100644
--- a/asteroid/walk.py
+++ b/asteroid/walk.py
@@ -518,7 +518,7 @@ def __unify(term, pattern, unifying = True ):
                 message_explicit("Success!", level="secondary")
                 return unifier
 
-    elif pattern[0] == 'deref':  # ('deref', v)
+    elif pattern[0] == 'deref':  # ('deref', v, bl)
         # v can be an AST representing any computation
         # that produces a pattern.
 
@@ -526,6 +526,18 @@ def __unify(term, pattern, unifying = True ):
 
         p = walk(pattern[1])
 
+        if pattern[2][0] != 'nil': # we have a binding term list
+            if p[1][0] != 'constraint':
+                raise ValueError(
+                    "binding term lists only supported for constraint patterns")
+            else: 
+                # construct a new constraint pattern with the binding term list in place
+                p = ('pattern',
+                        ('constraint',
+                            p[1][1],
+                            pattern[2]))
+
+
         message_explicit("{} -> {}", [gen_t2s(pattern), gen_t2s(p)], 
             level="secondary")
 
@@ -558,12 +570,29 @@ def __unify(term, pattern, unifying = True ):
             notify=True, increase=True
         )
 
+        p = pattern[1]
+        bl = pattern[2] # binding term list
+
         state.constraint_lvl += 1
-        unifier = unify(term,pattern[1])
+        unifier = unify(term,p)
         state.constraint_lvl -= 1
 
         message_explicit("[End] constraint pattern", decrease=True)
-        return [] #Return an empty unifier
+
+        if bl[0] == 'nil':
+            return [] #Return an empty unifier
+        else:
+            # binding list is non-empty, map variables
+            # that appear in the binding list into
+            # the returned unifier
+            new_unifier = []
+            for u in unifier:
+                ((ID,x),exp) = u
+                for bt in bl[1]:
+                    (BINDING_TERM, (ID,y), new_id) = bt
+                    if x == y:
+                        new_unifier += [(new_id,exp)]
+            return new_unifier
 
     elif term[0] != pattern[0]:  # nodes are not the same
         message_explicit("Fail: {} and {} are not the same",
@@ -1873,14 +1902,9 @@ def process_lineinfo(node):
 #########################################################################
 def deref_exp(node):
 
-    (DEREF, id_exp) = node
-    assert_match(DEREF, 'deref')
-
     # deref operators are only meaningful during pattern matching
-    # ignore during a value walk.
-    # NOTE: the second walk is necessary to interpret what we retrieved
-    # through the indirection
-    return walk(walk(id_exp))
+    # it is an error to have the deref operator appear in an expression
+    raise ValueError("dereferencing patterns is not valid in expressions.")
 
 #########################################################################
 def constraint_exp(node):
@@ -1888,11 +1912,9 @@ def constraint_exp(node):
     # Constraint-only pattern matches should not exist where only an
     # expression is expected. If we get here, we have come across this
     # situation.
-    # A constraint-only pattern match AST cannot be walked and therefor
+    # A constraint-only pattern match AST cannot be walked and therefore
     # we raise an error.
-    raise ValueError(
-        "constraint pattern: '{}' cannot be used as a constructor."
-        .format(term2string(node)))
+    raise ValueError("a constraint pattern cannot be used as an expression.")
 
 #########################################################################
 def set_ret_val(node):
@@ -2023,6 +2045,8 @@ def debug_walk(node, dbg):
 
 # a dictionary to associate tree nodes with node functions
 dispatch_dict = {
+    # Note: statement lists are now handled by separate functions outside
+    #       the walk function
     # statements - statements do not produce return values
     'lineinfo'      : process_lineinfo,
     'set-ret-val'   : set_ret_val,
diff --git a/docs/ADB.rst b/docs/ADB.rst
index 50abc4d2..0a1484de 100644
--- a/docs/ADB.rst
+++ b/docs/ADB.rst
@@ -2,20 +2,11 @@
 
 
 
-
-
-
-
-
-
-
-
-
-
 ..
    *** DO NOT EDIT; MACHINE GENERATED ***
 
 
+
 ===================
 ADB Reference Guide
 ===================
@@ -223,3 +214,4 @@ Explicit
 Quit
 ---------
 ``q(uit)`` Quits the current ADB session
+
diff --git a/docs/Asteroid in Action.rst b/docs/Asteroid in Action.rst
index 915c28ed..30e50b6b 100644
--- a/docs/Asteroid in Action.rst
+++ b/docs/Asteroid in Action.rst
@@ -2,20 +2,11 @@
 
 
 
-
-
-
-
-
-
-
-
-
-
 ..
    *** DO NOT EDIT; MACHINE GENERATED ***
 
 
+
 .. highlight:: none
 
 Asteroid in Action
@@ -33,10 +24,12 @@ Challenge: Hello, World!
 
 The canonical ``Hello, World!`` program.  The easiest way to write this in Asteroid is,
 ::
+
   load system io.
 
   io @println "Hello, World!".
 
+
 Output::
 
     Hello, World!
@@ -50,6 +43,7 @@ Challenge: Greet a person
 
 Here is our first solution using a separate function for each of the steps,
 ::
+
   load system io.
 
   io @print ("Enter your name: ").
@@ -57,19 +51,24 @@ Here is our first solution using a separate function for each of the steps,
   io @print ("Hello, "+name+"!").
 
 
+
 Letting the function ``input`` do the prompting,
 ::
+
   load system io.
 
   let name = io @input("Enter your name: ").
   io @println ("Hello, "+name+"!").
 
+
 Doing everything in one step,
 ::
+
   load system io.
 
   io @println ("Hello, "+io @input("Enter your name: ")+"!").
 
+
 Challenge: String length
 ^^^^^^^^^^^^^^^^^^^^^^^^
 
@@ -77,11 +76,13 @@ Challenge: String length
 
 In order to print the length of a string we can use the function ``len`` available in the ``util`` module,
 ::
+
   load system io.
 
   load "util".
   io @println (len("Hello!")).
 
+
 Output::
 
     6
@@ -89,10 +90,12 @@ Output::
 
 We can also use the string member function ``length`` in order to compute the length of the string,
 ::
+
   load system io.
 
   io @println ("Hello!" @length()).
 
+
 Output::
 
     6
@@ -106,6 +109,7 @@ Challenge: Unique digits
 In order to accomplish this we take advantage of the string ``explode`` function and the ``sort`` function on lists.
 Finally we use the ``reduce`` function to map a list with repeated digits to a list with unique digits,
 ::
+
   load system io.
 
   function unique with (x,y) do
@@ -122,6 +126,7 @@ Finally we use the ``reduce`` function to map a list with repeated digits to a l
   io @println digits.
   assert(digits == ["1","2","3"]).
 
+
 Output::
 
     [1,2,3]
@@ -139,6 +144,7 @@ Challenge: Reverse a string
 
 We use the ``explode`` function to turn a string into a list of characters. Then, we reverse the list and turn it back into a string using the ``join`` function,
 ::
+
   load system io.
 
   let str = "Hello, World!" @explode()
@@ -147,6 +153,7 @@ We use the ``explode`` function to turn a string into a list of characters. Then
   io @println str.
   assert(str == "!dlroW ,olleH").
 
+
 Output::
 
     !dlroW ,olleH
@@ -157,12 +164,14 @@ Challenge: Removing blanks from a string
 
 > Remove leading, trailing, and double spaces from a given string.
 ::
+
   load system io.
   let str = "   Hello  ,   World    !   " @trim()
                                           @replace("  ","").
   io @println str.
   assert(str == "Hello, World!").
 
+
 Output::
 
     Hello, World!
@@ -177,6 +186,7 @@ In this task, we will form the ``CamelCase`` variable for names from a given phr
 Names created in this style are built of several words, each of which starts
 with a capital letter.
 ::
+
   load system io.
 
   function title with w do
@@ -199,6 +209,7 @@ with a capital letter.
   io @println camel_str.
   assert(camel_str == "OnceUponATime").
 
+
 Output::
 
     OnceUponATime
@@ -209,6 +220,7 @@ Challenge: Incrementing filenames
 
 > Generate a list of filenames like file1.txt, file2.txt, etc.
 ::
+
   load system io.
 
   let root = "file".
@@ -218,6 +230,7 @@ Challenge: Incrementing filenames
       io @println (root+i+ext).
   end
 
+
 Output::
 
     file1.txt
@@ -234,6 +247,7 @@ Challenge: Random passwords
 
 In our solution we take advantage of Asteroid's ``Pick`` object.  The ``Pick`` object maintains a list of items that we can randomly select from using the ``pick`` member function.  As input to the ``Pick`` object, we compute a bunch of lists of characters that are useful for password construction.  The function ``achar`` converts a decimal ASCII code to a single character string.
 ::
+
   load system io.
   load system type.
   load system util.
@@ -257,6 +271,7 @@ In our solution we take advantage of Asteroid's ``Pick`` object.  The ``Pick`` o
 
   assert (pwd == "e3zvshdbS43brt#")
 
+
 Output::
 
     e3zvshdbS43brt#
@@ -277,6 +292,7 @@ to RNA happens according to the following table:
 
 We will solve this programming problem using Asteroid's first-class patterns. We could have solved this with just testing equality on DNA characters. However, using first-class patterns is more general and can be applied to problems with a more structured mapping relationship.
 ::
+
   load system io.
 
   let dna2rna_table =
@@ -304,6 +320,7 @@ We will solve this programming problem using Asteroid's first-class patterns. We
 
   assert(rna_seq == "UGGUAGUCAG").
 
+
 Output::
 
     UGGUAGUCAG
@@ -321,6 +338,7 @@ For example, if N is 4, then the letter e becomes a, f is transformed to b,
 etc. The alphabet is looped so that z becomes v, and letters a to d become
 w to z.
 ::
+
   load system io.
   load system util.
 
@@ -362,6 +380,7 @@ w to z.
 
   assert (decoded_msg == "hello, world!")
 
+
 Output::
 
     dahhk, sknhz!
@@ -382,12 +401,14 @@ In program outputs, it is often required to print some number followed by a noun
 
 If there is only one file, then the phrase should be ``1 file found`` instead.
 ::
+
   load system io.
 
   for n in 0 to 5 do
       io @println (n+" file"+("s " if n>1 or n==0 else " ")+"found").
   end
 
+
 Output::
 
     0 files found
@@ -406,6 +427,7 @@ Challenge: The most frequent word
 In our solution we use a hash table to count the number of word occurences.
 ::
 
+
   load system io.
   load system util.
   load system hash.
@@ -464,6 +486,7 @@ In our solution we use a hash table to count the number of word occurences.
 
   assert (most_frequent_word == "sed").
 
+
 Output::
 
     sed
@@ -480,6 +503,7 @@ There are two loops (see also Task 17, The longest palindrome) over the first
 string (``stra``). These use the index method to search for the substring in the
 second string (``strb``).
 ::
+
   load system io.
 
   let stra = "the quick brown fox jumps over the lazy dog".
@@ -503,6 +527,7 @@ second string (``strb``).
 
   assert (common == " fox ").
 
+
 Output::
 
     The longest common substring is ' fox '.
@@ -515,6 +540,7 @@ Challenge: Anagram test
 
 An anagram is a word, phrase, or name formed by rearranging the letters of another, such as ``cinema``, formed from ``iceman``.
 ::
+
   load system io.
 
   let str1 = "cinema".
@@ -534,6 +560,7 @@ An anagram is a word, phrase, or name formed by rearranging the letters of anoth
 
   assert (normalize(str1) == normalize(str2)).
 
+
 Output::
 
     Anagrams
@@ -547,6 +574,7 @@ Challenge: Palindrome test
 A palindrome is a string that can be read from both ends: left to right or right
 to left.
 ::
+
   load system io.
 
   let str = "Was it a rat I saw?".
@@ -568,6 +596,7 @@ to left.
 
   assert (clean_str == clean_str @flip()).
 
+
 Output::
 
     Palindromic
@@ -586,6 +615,7 @@ Now, extract the substring and do the check similar to the solution of Task
 without taking into account the non-letter characters, but saving the result as
 part of the original string.
 ::
+
   load system io.
 
   let str = "Hello, World!".
@@ -619,6 +649,7 @@ part of the original string.
 
   io @println longest_palindrome.
 
+
 Output::
 
     o, Wo
@@ -631,6 +662,7 @@ Challenge: Finding duplicate texts
 
 We do this by finding and hashing N-grams after the appropriate preprocessing.  We will use ``N=3``.
 ::
+
   load system io.
   load system hash.
 
@@ -748,6 +780,7 @@ We do this by finding and hashing N-grams after the appropriate preprocessing.
       io @println (n_gram+": "+cnt).
   end
 
+
 Output::
 
     lorem ipsum dolor: 2
@@ -773,17 +806,20 @@ Challenge: Pi
 
 > Print the value of pi.
 ::
+
   load system io.
   load system math. -- definition of pi
 
   io @println (math @pi).
 
+
 Output::
 
     3.141592653589793
 
 Other constants are also available.
 ::
+
   load system io.
   load system math.
 
@@ -792,6 +828,7 @@ Other constants are also available.
 
   assert (math @tau == 2 * math @pi)
 
+
 Output::
 
     2.718281828459045
@@ -805,6 +842,7 @@ Challenge: Factorial!
 
 By definition, the factorial of a positive integer number N is a product of all the integers numbering from 1 to N, including N. Our first solution is based on the direct implementation of the definition above using the list ``reduce`` function.
 ::
+
   load system io.
 
   let n = 3.
@@ -812,6 +850,7 @@ By definition, the factorial of a positive integer number N is a product of all
   io @println fact.
   assert (fact == 6).
 
+
 Output::
 
     6
@@ -828,6 +867,7 @@ where :math:`x \in Int`.
 Here, each case specifies what value the function should return if
 the predicate applied to the input is true.  The last case is of some interest because it states that the function is undefined for negative integers.
 ::
+
   load system io.
 
   let POS_INT = pattern with (x:%integer) if x > 0.
@@ -845,6 +885,7 @@ the predicate applied to the input is true.  The last case is of some interest b
   io @println ("The factorial of 3 is: " + fact (3)).
   assert (fact(3) == 6).
 
+
 Output::
 
     The factorial of 3 is: 6
@@ -864,6 +905,7 @@ You can assign two values at a time (**Challenge: Swap two values**). You can us
 
 Here we give an iterative solutions.  It is clear that there exists a trivial recursive solution by implementing the above formula.
 ::
+
   load system io.
 
   let n = 10. -- compute the 10th Fib number
@@ -876,6 +918,7 @@ Here we give an iterative solutions.  It is clear that there exists a trivial re
   io @println f_1.
   assert (f_1 == 55)
 
+
 Output::
 
     55
@@ -888,6 +931,7 @@ Challenge: Print squares
 
 Of course this is straightforward, with a ``for-loop`` over a list.  Here we show another solution using the list ``map`` function.
 ::
+
   load system io.
 
   let sq = [1 to 10] @map(lambda with x do return x*x).
@@ -896,6 +940,7 @@ Of course this is straightforward, with a ``for-loop`` over a list.  Here we sho
 
   assert (sq == [1,4,9,16,25,36,49,64,81,100])
 
+
 Output::
 
     [1,4,9,16,25,36,49,64,81,100]
@@ -908,6 +953,7 @@ Challenge: Powers of two
 
 Just as in the previous challenge, we skip the naive loop solution and give a solution using the ``map`` function.
 ::
+
   load system io.
   load system math.
 
@@ -917,6 +963,7 @@ Just as in the previous challenge, we skip the naive loop solution and give a so
 
   assert (p2 == [1,2,4,8,16,32,64,128,256,512])
 
+
 Output::
 
     [1,2,4,8,16,32,64,128,256,512]
@@ -929,6 +976,7 @@ Challenge: Odd and even numbers
 
 We start with printing the first ten odd numbers,
 ::
+
   load system io.
   load system math.
 
@@ -940,6 +988,7 @@ We start with printing the first ten odd numbers,
   io @println odd.
   assert(odd == [1,3,5,7,9])
 
+
 Output::
 
     [1,3,5,7,9]
@@ -947,6 +996,7 @@ Output::
 
 Now the even numbers,
 ::
+
   load system io.
   load system math.
 
@@ -958,6 +1008,7 @@ Now the even numbers,
   io @println even.
   assert(even == [2,4,6,8,10])
 
+
 Output:
 ::
 
@@ -971,6 +1022,7 @@ Challenge: Compare numbers approximately
 
 Comparing non-integer numbers (which are represented as floating-point numbers) is often a task that requires approximate comparison.  In Asteroid this can be accomplished with the ``isclose`` function availabel in the ``math`` module.
 ::
+
   load system io.
   load system math.
 
@@ -981,6 +1033,7 @@ Comparing non-integer numbers (which are represented as floating-point numbers)
   assert (math @isclose(2.0,2.00001,0.0001)).
 
 
+
 Challenge: Prime numbers
 ^^^^^^^^^^^^^^^^^^^^^^^^
 
@@ -988,6 +1041,7 @@ Challenge: Prime numbers
 
 Prime numbers are those that can be divided only by 1, and by themselves.
 ::
+
   load system io.
   load system math.
 
@@ -1010,6 +1064,7 @@ Prime numbers are those that can be divided only by 1, and by themselves.
   assert (isprime(17)).
   assert (not isprime(15)).
 
+
 Output:
 ::
 
@@ -1022,6 +1077,7 @@ Challenge: List of prime numbers
 
 > Print the list of the first ten prime numbers.
 ::
+
   load system io.
   load system math.
 
@@ -1047,6 +1103,7 @@ Challenge: List of prime numbers
       end
   end
 
+
 Output:
 ::
 
@@ -1069,6 +1126,7 @@ Challenge: Prime factors
 
 Prime factors are the prime numbers that divide the given integer number exactly.
 ::
+
   load system io.
   load system math.
 
@@ -1111,6 +1169,7 @@ Prime factors are the prime numbers that divide the given integer number exactly
 
   assert (factors == [3,5,11])
 
+
 Output:
 ::
 
@@ -1124,6 +1183,7 @@ Challenge: Reducing a fraction
 
 5/15 and 16/280 are examples of fractions that can be reduced. The final results of this task are 1/3 and 2/35. Generally, the algorithm of reducing a fraction requires searching for the greatest common divisor, and then dividing both numerator and denominator by that number.  For our solution we use the function ``gcd`` available in the ``math`` module.
 ::
+
   load system io.
   load system math.
 
@@ -1141,6 +1201,7 @@ Challenge: Reducing a fraction
   -- show that original and reduced fraction are the same value
   assert (a/b == numerator/denominator).
 
+
 Output:
 ::
 
@@ -1155,6 +1216,7 @@ Challenge: Divide by zero
 
 Asteroid is an eager language, that is, expressions are evaluated as early as possible.  We can trap division-by-zero errors using a try-catch block.
 ::
+
   load system io.
 
   try
@@ -1164,6 +1226,7 @@ Asteroid is an eager language, that is, expressions are evaluated as early as po
   end
   io @println "We are still alive...".
 
+
 Output:
 ::
 
@@ -1181,6 +1244,7 @@ Challenge: Generating random numbers
 
 Asteroid has two random number generation functions: ``random()`` generates a random real value in the interval $[0.0,1.0)$ and ``randint(a,b)`` that generates a random value in the interval $[a,b]$.  The type of the random value generated depends on the type of the values a and b specifying the interval.
 ::
+
   load system io.
   load system random.
   load system util.
@@ -1199,6 +1263,7 @@ Asteroid has two random number generation functions: ``random()`` generates a ra
   io @println (randint(0.0,type @toreal(n))).
   io @println (randint(0,n)).
 
+
 Output:
 ::
 
@@ -1224,6 +1289,7 @@ This algorithm is a simple method of generating short sequences of four-digit ra
 
 To illustrate it with an example, let’s take the number 1234 as the seed. On step 2, it becomes 1522756; after step 3, 01522756. Finally, step 4 extracts the number 5227.
 ::
+
   load system io.
   load system util.
   load system type.
@@ -1242,6 +1308,7 @@ To illustrate it with an example, let’s take the number 1234 as the seed. On s
 
   assert (rval == 5227)
 
+
 Output:
 ::
 
@@ -1257,6 +1324,7 @@ The quality of the built-in generator of random numbers fully depends on the alg
 
 In our solution, we generate 10 random integers between 0 and 9. We then count how many times each of the integers have been generated.  If it is a decent random number generator, all numbers should have been generated roughly an equal number of times.
 ::
+
   load system io.
   load system random.
 
@@ -1269,6 +1337,7 @@ In our solution, we generate 10 random integers between 0 and 9. We then count h
 
   io @println hist.
 
+
 Output:
 ::
 
@@ -1286,6 +1355,7 @@ Challenge: Distance between two points
 There are two points on a surface, each with their own coordinates, x and y. The task is to find the distance between these two points.
 A straightforward solution would be to use the Pythagorean theorem:
 ::
+
   load system io.
   load system math.
 
@@ -1296,6 +1366,7 @@ A straightforward solution would be to use the Pythagorean theorem:
 
   assert (d == 2.23606797749979)
 
+
 Output:
 ::
 
@@ -1310,6 +1381,7 @@ Another approach is using the math identity,
 
 where ``.`` represents the dot product. In our case ``a`` would be the distance vector between points ``x`` and ``y``,
 ::
+
   load system io.
   load system math.
   load system vector.
@@ -1322,6 +1394,7 @@ where ``.`` represents the dot product. In our case ``a`` would be the distance
 
   assert (d == 2.23606797749979)
 
+
 Output:
 ::
 
@@ -1343,6 +1416,7 @@ Standard deviation is a statistical term that shows how compact data distributio
 
 where :math:`n` is the number of elements in the array :math:`x`; :math:`\bar{x}` is its average value (**Challenge: Average on an array**).
 ::
+
   load system io.
   load system math.
 
@@ -1357,6 +1431,7 @@ where :math:`n` is the number of elements in the array :math:`x`; :math:`\bar{x}
 
   assert (sigma == 420.96248961952256)
 
+
 Output:
 ::
 
@@ -1379,6 +1454,7 @@ The conversion formulae between the Cartesian and polar systems, which is valid
 
 These expressions can be implemented as-is in the code:
 ::
+
   load system io.
   load system math.
 
@@ -1409,6 +1485,7 @@ These expressions can be implemented as-is in the code:
   -- we started with
   assert (math @isclose(1,x,0.0001) and math @isclose(2,y,0.0001)).
 
+
 Output:
 ::
 
@@ -1419,6 +1496,7 @@ For the **negative** ``x`` and ``y``, the Cartesian-to-polar conversion is a bit
 or smaller than ``pi``. When ``x`` is zero, it is either ``-pi/2`` or ``pi/2``.
 All these variants can be implemented by using ``with`` clauses and conditional matching, as demonstrated below:
 ::
+
   load system io.
   load system math.
   load system util.
@@ -1467,6 +1545,7 @@ All these variants can be implemented by using ``with`` clauses and conditional
   -- we started with
   assert (math @isclose(-3,x,0.0001) and math @isclose(5,y,0.0001)).
 
+
 Output:
 ::
 
@@ -1482,6 +1561,7 @@ The Monte Carlo method is a statistical method of calculating data whose formula
 
 To calculate the area of a circle with a radius of 1, pairs of random numbers between −1 and 1 are generated. These pairs represent the points in the square in the center of coordinates with sides of length 2. The area of the square is thus 4. If the distance between the random point and the center of the square is less than 1, then this point is located inside the circle of that radius. Counting the number of points that landed inside the circle and the number of points outside the circle gives the approximate value of the area of the circle, as soon as the area of the square is known. Here is the program.
 ::
+
   load system io.
   load system math.
   load system random.
@@ -1505,6 +1585,7 @@ To calculate the area of a circle with a radius of 1, pairs of random numbers be
 
   assert (area == 3.1392).
 
+
 Output:
 ::
 
@@ -1519,6 +1600,7 @@ Challenge: Guess the number
 First, a random number needs to be generated. Then the program must
 ask for the initial guess and enter the loop, which compares the guess with the generated number.
 ::
+
   load system io.
   load system random.
   load system util.
@@ -1538,6 +1620,7 @@ ask for the initial guess and enter the loop, which compares the guess with the
   end
   io @println "Yes, this is it!".
 
+
 Challenge: Binary to integer
 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
@@ -1545,6 +1628,7 @@ Challenge: Binary to integer
 
 In Asteroid this is straightforward using the built-in ``tointeger`` function, passing it a string representation of the binary number and the base.
 ::
+
   load system io.
   load system type.
 
@@ -1554,6 +1638,7 @@ In Asteroid this is straightforward using the built-in ``tointeger`` function, p
 
   assert (int == 45).
 
+
 Output:
 ::
 
@@ -1567,6 +1652,7 @@ Challenge: Integer as binary, octal, and hex
 
 In Asteroid this is easily done with the ``tobase`` function.
 ::
+
   load system io.
   load system type.
 
@@ -1584,6 +1670,7 @@ In Asteroid this is easily done with the ``tobase`` function.
   assert (tointeger(tobase(val,8),8) == val).
   assert (tointeger(tobase(val,16),16) == val).
 
+
 Output:
 ::
 
@@ -1599,6 +1686,7 @@ Challenge: Sum of digits
 
 Pretty straightforward using string and list manipulation.
 ::
+
   load system io.
   load system type.
 
@@ -1612,6 +1700,7 @@ Pretty straightforward using string and list manipulation.
 
   assert (s == 49).
 
+
 Output:
 ::
 
@@ -1625,6 +1714,7 @@ Challenge: Bit counter
 
 If we remove all the zeros from a binary number, then we are left with only ``1`` characters which we can then count.
 ::
+
   load system io.
 
   let bits = "1010101" @replace("0","")
@@ -1633,6 +1723,7 @@ If we remove all the zeros from a binary number, then we are left with only ``1`
 
   assert (bits == 4).
 
+
 Output:
 ::
 
@@ -1646,6 +1737,7 @@ Challenge: Compose the largest number
 
 The easiest way to achieve that is to treat the numbers as strings, sort them alphabetically in descending order, concatenate the pieces to a single string, and get the resulting integer.
 ::
+
   load system io.
   load system type.
 
@@ -1654,6 +1746,7 @@ The easiest way to achieve that is to treat the numbers as strings, sort them al
 
   assert (a == 8675451).
 
+
 Output:
 ::
 
@@ -1671,6 +1764,7 @@ Let’s use the algorithm that keeps the table of pre-calculated sequences of Ro
 
 In the program below, there are four such sequences: for thousands, hundreds, tens, and ones. The program iterates over the digits of the number in the decimal representation and chooses one of the values from the array of lists stored in the ``roman_hash`` table.
 ::
+
   load system io.
   load system math.
   load system util.
@@ -1698,6 +1792,7 @@ In the program below, there are four such sequences: for thousands, hundreds, te
 
   assert (roman == "MMXVIII")
 
+
 Output:
 ::
 
@@ -1724,6 +1819,7 @@ For the larger numbers (21 to 99), there are two cases. If the number is dividab
 
 The zero name appears only in the case when the given number is zero.
 ::
+
   load system io.
   load system math.
 
@@ -1758,6 +1854,7 @@ The zero name appears only in the case when the given number is zero.
   io @println (spell_number 987654).
   io @println (spell_number 1001).
 
+
 Output:
 ::
 
@@ -1782,6 +1879,7 @@ In Asteroid, there is no need to use temporary variables to swap the values of t
 
 Consider the complete program:
 ::
+
   load system io.
 
   let (a,b) = (10,20).
@@ -1790,6 +1888,7 @@ Consider the complete program:
 
   assert ((a,b) is (20,10)).
 
+
 Output:
 ::
 
@@ -1803,6 +1902,7 @@ This program prints the swapped values:
 
 This approach also works with elements of an array:
 ::
+
   load system io.
 
   let a = [3,5,7,4].
@@ -1811,6 +1911,7 @@ This approach also works with elements of an array:
 
   assert (a is [3,5,4,7]).
 
+
 Output:
 ::
 
@@ -1822,6 +1923,7 @@ Challenge: Reverse a list
 
 > Print the given list in reverse order.
 ::
+
   load system io.
 
   let a = [10, 20, 30, 40, 50].
@@ -1829,6 +1931,7 @@ Challenge: Reverse a list
 
   assert(a == [50,40,30,20,10]).
 
+
 Output:
 ::
 
@@ -1842,6 +1945,7 @@ Challenge: Rotate a list
 
 Asteroid does not have a built-in ``rotate`` function. However, such a function is easily constructed through slicing lists (see ``vix`` below).
 ::
+
   load system io.
   load system math.
 
@@ -1861,6 +1965,7 @@ Asteroid does not have a built-in ``rotate`` function. However, such a function
 
   assert(b == [7,9,11,13,15,1,3,5] and c == [11,13,15,1,3,5,7,9]).
 
+
 Output:
 ::
 
@@ -1876,6 +1981,7 @@ Challenge: Randomize an array
 
 This is easily accomplished with the built-in ``shuffle``.
 ::
+
   load system io.
   load system random.
 
@@ -1885,6 +1991,7 @@ This is easily accomplished with the built-in ``shuffle``.
 
   assert(b == [20,6,15,5,10,14,16,19,7,13,18,11,2,12,3,17,8,9,1,4]).
 
+
 Output:
 ::
 
@@ -1898,6 +2005,7 @@ Challenge: Incrementing array elements
 
 For this we use Asteroid's ``vector`` module, which can handle incrementing a vector with a scalar.
 ::
+
   load system io.
   load system vector.
 
@@ -1907,6 +2015,7 @@ For this we use Asteroid's ``vector`` module, which can handle incrementing a ve
 
   assert(b == [2,3,4,5,6,7,8,9,10,11]).
 
+
 Output:
 ::
 
@@ -1920,6 +2029,7 @@ Challenge: Adding up two arrays
 
 Again, here we take advantage of Asteroid's ``vector`` module.  Note that the two vectors have to be of the same length in order to add them together.
 ::
+
   load system io.
   load system vector.
 
@@ -1930,6 +2040,7 @@ Again, here we take advantage of Asteroid's ``vector`` module.  Note that the tw
 
   assert(c == [40,42,44,46,48,50,52,54,56,58,60]).
 
+
 Output:
 ::
 
@@ -1938,6 +2049,7 @@ Output:
 
 The vector module defines a function called ``op`` that allows you to combine two vectors using any arbitrary binary function.  Rewriting the above program using ``op``,
 ::
+
   load system io.
   load system vector.
 
@@ -1948,6 +2060,7 @@ The vector module defines a function called ``op`` that allows you to combine tw
 
   assert(c == [40,42,44,46,48,50,52,54,56,58,60]).
 
+
 Output:
 ::
 
@@ -1956,6 +2069,7 @@ Output:
 
 As we said above, any arbitrary binary function. Consider the relational operator ``<`` expressed as a lambda function,
 ::
+
   load system io.
   load system vector.
   load system random.
@@ -1969,6 +2083,7 @@ As we said above, any arbitrary binary function. Consider the relational operato
 
   assert(c == [false,true,false,false,false,true,false,false,true,true]).
 
+
 Output:
 ::
 
@@ -1983,6 +2098,7 @@ appear in the second one.
 
 Here we use Asteroid's ``set`` module.
 ::
+
   load system io.
   load system set.
 
@@ -1993,6 +2109,7 @@ Here we use Asteroid's ``set`` module.
 
   assert(c @sort() == [1,2,3,4]).
 
+
 Output:
 ::
 
@@ -2007,6 +2124,7 @@ Challenge: Sum of the elements of an array
 
 > Find the sum of the elements of an array of integers.
 ::
+
   load system io.
 
   let a = [4, 6, 8, 1, 0, 58, 1, 34, 7, 4, 2].
@@ -2015,6 +2133,7 @@ Challenge: Sum of the elements of an array
 
   assert (s == 125).
 
+
 Output:
 ::
 
@@ -2023,6 +2142,7 @@ Output:
 
 If summing up elements that are greater than 10,
 ::
+
   load system io.
 
   let a = [4, 6, 8, 1, 0, 58, 1, 34, 7, 4, 2].
@@ -2032,6 +2152,7 @@ If summing up elements that are greater than 10,
 
   assert (s == 92).
 
+
 Output:
 ::
 
@@ -2043,6 +2164,7 @@ Challenge: Average of an array
 
 > Find the average value of the given array of numbers.
 ::
+
   load system io.
 
   let a = [7, 11, 34, 50, 200].
@@ -2051,6 +2173,7 @@ Challenge: Average of an array
 
   assert (avg == 60).
 
+
 Output:
 ::
 
@@ -2062,12 +2185,14 @@ Challenge: Is an element in a list?
 
 > Tell if the given value is in the list.
 ::
+
   load system io.
 
   let array = [10, 14, 0, 15, 17, 20, 30, 35].
   let x = 17.
   io @println ((x+" is in the list") if array @member(x) else (x+" is not in the list")).
 
+
 Output:
 ::
 
@@ -2076,6 +2201,7 @@ Output:
 
 We can also use a reduction function to solve this,
 ::
+
   load system io.
 
   let array = [10, 14, 0, 15, 17, 20, 30, 35].
@@ -2087,6 +2213,7 @@ We can also use a reduction function to solve this,
       io @println (x+" is not in the list").
   end
 
+
 Output:
 ::
 
@@ -2100,6 +2227,7 @@ Challenge: First odd number
 
 The easiest way to do this is with a reduction,
 ::
+
   load system io.
   load system math.
   load system util.
@@ -2111,6 +2239,7 @@ The easiest way to do this is with a reduction,
   let odd = array @reduce(lambda with (acc,i) do return i if type @isnone(acc) and mod(i,2) else acc,none).
   io @println odd.
 
+
 Output:
 ::
 
@@ -2122,6 +2251,7 @@ Challenge: Take every second element
 
 > Form a new array by picking every second element from the original array.
 ::
+
   load system io.
   load system math.
 
@@ -2130,6 +2260,7 @@ Challenge: Take every second element
 
   assert (array == [21,23,25,27,29]).
 
+
 Output:
 ::
 
@@ -2138,6 +2269,7 @@ Output:
 
 We can use an index vector to accomplish  the same thing,
 ::
+
   load system io.
   load system math.
 
@@ -2147,6 +2279,7 @@ We can use an index vector to accomplish  the same thing,
 
   assert (array == [21,23,25,27,29]).
 
+
 Output:
 ::
 
@@ -2158,6 +2291,7 @@ Challenge: Number of occurrences in an array
 
 > Count how many times a particular element appears in the array.
 ::
+
   load system io.
   load system math.
 
@@ -2177,6 +2311,7 @@ Challenge: Number of occurrences in an array
 
   assert (cnt == 2).
 
+
 Output:
 ::
 
@@ -2190,6 +2325,7 @@ Challenge: Finding unique elements
 
 Converting a list to a set will remove all duplicate elements in the list.
 ::
+
   load system io.
   load system set.
 
@@ -2214,6 +2350,7 @@ Challenge: Minimum and maximum
 
 > Find the minimum and the maximum numbers in the given list of integers.
 ::
+
   load system io.
 
   function max with lst:%list do
@@ -2234,6 +2371,7 @@ Challenge: Minimum and maximum
 
   assert (a == 15 and b == 2).
 
+
 Output:
 ::
 
@@ -2246,6 +2384,7 @@ Challenge: Increasing sequences
 
 > Check if the given array contains increasing (or decreasing) numbers.
 ::
+
   load system io.
   load system type.
 
@@ -2256,6 +2395,7 @@ Challenge: Increasing sequences
 
   assert (b).
 
+
 Output:
 ::
 
@@ -2296,6 +2436,7 @@ with its transpose,
 
 The procedure:
 ::
+
   load system io.
 
   function transpose with m do
@@ -2356,6 +2497,7 @@ The procedure:
 
   assert(mt == [[1,3,5],[2,4,6]]).
 
+
 Output:
 ::
 
@@ -2389,6 +2531,7 @@ Challenge: Sort hashes by parameter
 
 This task is commonly performed to sort items where the sortable parameter is one of the values in the hash. For example, sorting a list of people by age.
 ::
+
   load system io.
   load system hash.
   load system sort.
@@ -2420,6 +2563,7 @@ This task is commonly performed to sort items where the sortable parameter is on
 
   assert (sort @sort(pairs,lst) == [("Pete",20),("Joe",23),("Billie",40),("Brandi",43)])
 
+
 Output:
 ::
 
@@ -2433,6 +2577,7 @@ Challenge: Count hash values
 
 For example, a hash is a collection mapping a car’s license plate to the colour of the car or a passport number to the name of the street where the person lives. In the first example, the task is to count how many cars of each colour there are. In the second example, we have to say how many people live on each street. But let’s simply count the colours of fruit.
 ::
+
   load system io.
   load system hash.
   load system sort.
@@ -2467,6 +2612,7 @@ For example, a hash is a collection mapping a car’s license plate to the colou
 
   io @println (sort @sort(pairs,color_lst)).
 
+
 Output:
 ::
 
@@ -2480,6 +2626,7 @@ Challenge: Product table
 
 We will do this with an outer loop  and a ``map`` function.
 ::
+
   load system io.
   load system type.
 
@@ -2493,6 +2640,7 @@ We will do this with an outer loop  and a ``map`` function.
       io @println ([1 to 10] @map(lambda with x do return format(i*x)) @join(" ")).
   end
 
+
 Output:
 ::
 
@@ -2555,6 +2703,7 @@ We then add them together,
 
 The only thing that is left to do is to iterate appropiately and format the output.
 ::
+
   load system io.
   load system vector.
   load system util.
@@ -2576,6 +2725,7 @@ The only thing that is left to do is to iterate appropiately and format the outp
       io @println (r @map(lambda with v do return type @tostring v) @join(" ")).
   end
 
+
 Output:
 ::
 
@@ -2590,3 +2740,4 @@ Output:
 
 The program prints the first seven rows of the Pascal triangle. The rows are not centred, and are aligned to the left side.
 As an extra exercise, modify the program so that it prints the triangle as it is shown at the beginning of this task. For example, you can first generate rows and keep them in a separate array and then, knowing the length of the longest string, add some spaces in front of the rows before printing them.
+
diff --git a/docs/Quickstart Tutorial.rst b/docs/Quickstart Tutorial.rst
index 7018840a..96c2c2cb 100644
--- a/docs/Quickstart Tutorial.rst
+++ b/docs/Quickstart Tutorial.rst
@@ -2,20 +2,11 @@
 
 
 
-
-
-
-
-
-
-
-
-
-
 ..
    *** DO NOT EDIT; MACHINE GENERATED ***
 
 
+
 .. highlight:: none
 
 .. role:: raw-html(raw)
@@ -232,3 +223,4 @@ Some important things to note in Asteroid:
 * If you see a line that looks like (``x:%integer``), that is used to match any value of a given type. (The ``%integer`` pattern matches any integer value and can be used with any other type in Asteroid.)
 
 If you would like more information about Asteroid, please see the Asteroid `reference guide <https://asteroid-lang.readthedocs.io/en/latest/Reference%20Guide.html#>`_  and `user guide <https://asteroid-lang.readthedocs.io/en/latest/Asteroid%20User%20Guide.html>`_.
+
diff --git a/docs/Reference Guide.rst b/docs/Reference Guide.rst
index 8e8d8993..c5b9c8f2 100644
--- a/docs/Reference Guide.rst
+++ b/docs/Reference Guide.rst
@@ -2,20 +2,11 @@
 
 
 
-
-
-
-
-
-
-
-
-
-
 ..
    *** DO NOT EDIT; MACHINE GENERATED ***
 
 
+
 .. highlight:: none
 
 Asteroid Reference Guide
@@ -428,7 +419,7 @@ we are dealing with a list,
 ::
       let [h | t] = [1,2,3].
 
-The ``is`` Predicate
+The Is Predicate
 %%%%%%%%%%%%%%%%%%%%
 
 Syntax: ``exp IS pattern``
@@ -449,7 +440,7 @@ Example,
          io @println "not matched".
       end
 
-The ``in`` Predicate
+The In Predicate
 %%%%%%%%%%%%%%%%%%%%
 
 Syntax: ``exp IN list_exp``
@@ -521,7 +512,7 @@ First-Class Patterns
 %%%%%%%%%%%%%%%%%%%%
 
 | Syntax: ``PATTERN exp``
-| Syntax: ``* exp``
+| Syntax: ``'*' exp (BIND '[' ID (AS ID)? (',' ID (AS ID)?)*']')?``
 
 This construction allows the user to construct a pattern as a value using
 the ``pattern`` keyword.  The advantage of patterns as values is that they
@@ -540,6 +531,21 @@ variables, e.g.
 Here the pair ``(1,2)`` is matched against the pattern stored in the variable ``p``
 such that ``x`` is bound to the value ``2``.
 
+The optional ``bind`` term together with an appropriate list of variable names 
+allows the user to selectively project variable bindings from a constraint pattern 
+into the current scope.  The ``as`` keyword allows you to rename those bindings.
+Consider the following program,
+::
+      let Pair = pattern %[(x,y)]%.
+
+      -- bindings of the variables x and y are now visible as a and y respetively
+      let *Pair bind [x as a, y] = (1,2).  
+      assert( a == 1).
+      assert(y == 2).
+
+At the second  ``let`` statement we bind the ``x`` as ``a`` and ``y`` from the hidden scope 
+of the constraint pattern into our current scope.
+
 Type Patterns
 %%%%%%%%%%%%%
 
@@ -559,8 +565,8 @@ Named Patterns
 Syntax: ``name_exp ':' pattern``
 
 Named patterns allow you to bind the term matched by the pattern to a variable.
-Here the name expression has to evaluate to something that looks like a variable,
-object member variable, or array location.
+Here the name expression has to evaluate to either a variable,
+object member variable, or list location.
 
 Example,
 ::
@@ -569,6 +575,15 @@ Example,
 The variable ``x`` will be bound to the value of ``val`` if that value matches the
 type pattern ``%integer``.
 
+Named patterns are a syntactic short hand for the equivalent conditional pattern,
+::
+      name_exp if name_exp is pattern
+
+That means the following two ``let`` statements are equivalent,
+::
+      let x:(q,p) = (1,2).
+      let x if x is (q,p) = (1,2).
+
 Conditional Patterns
 %%%%%%%%%%%%%%%%%%%%
 
@@ -618,6 +633,7 @@ where ``<syntactic unit>*`` means zero or more occurrences of the syntactic unit
 are written in quotes.
 ::
 
+
   ////////////////////////////////////////////////////////////////////////////////////////
   // statements
 
@@ -724,7 +740,7 @@ are written in quotes.
     | FALSE
     | NONE
     | ID
-    | '*' call_or_index   
+    | '*' call_or_index  binding_list? 
     | NOT call_or_index
     | MINUS call_or_index
     | PLUS call_or_index
@@ -735,6 +751,14 @@ are written in quotes.
     | function_const
     | TYPEMATCH           // TYPEMATCH == '%'<typename>
 
+// Note: binding lists are only supported for constraint patterns
+
+  binding_list
+    : BIND '[' binding_term (',' binding_term)* ']'
+
+  binding_term
+    : ID (AS ID)?
+
   tuple_stuff
     : exp (',' exp?)*
     | empty
@@ -747,6 +771,7 @@ are written in quotes.
     : LAMBDA body_defs
 
 
+
 Builtin Functions
 -----------------
 
@@ -969,12 +994,14 @@ The `math <https://github.com/asteroid-lang/asteroid/blob/master/asteroid/module
 
 An example,
 ::
+
     load system io.
     load system math.
 
     let x = math @sin( math @pi / 2 ).
     io @println("The sine of pi / 2 is " + x + ".").
 
+
 Pick
 ^^^^
 
@@ -983,6 +1010,7 @@ pick objects that allow a user to randomly pick items from a list using the ``pi
 The ``pick`` function can be called with ``n:%integer`` and returns a list of ``n`` randomly picked objects from the object list.
 Here is a simple use case
 ::
+
    load system io.
    load system pick.
 
@@ -1026,12 +1054,14 @@ The ``sort`` function makes use of a user-defined order predicate on the list's
 perform the sort. The ``Quicksort`` is the underlying sort algorithm.
 The following is a simple example,
 ::
+
    load system io.
    load system sort.
    let sl = sort @sort((lambda with (x,y) do return true if x<y else false),
                        [10,5,110,50]).
     io @println sl.
 
+
 prints the sorted list::
 
   [5,10,50,110]
@@ -1053,6 +1083,7 @@ The following stream interface functions are available,
 
 A simple use case.
 ::
+
    load system io.
    load system stream.
 
@@ -1095,6 +1126,7 @@ The `type <https://github.com/asteroid-lang/asteroid/blob/master/asteroid/module
 
 Here is a program that exercises some of the string formatting options,
 ::
+
     load system io.
     load system type.
     load system math.
@@ -1116,6 +1148,7 @@ Here is a program that exercises some of the string formatting options,
     let r = type @tostring(math @pi,type @stringformat(6,3)).
     io @println r.
 
+
 The output of the program is,
 ::
 
@@ -1136,6 +1169,7 @@ Notice the right justification of the various values within the given string len
 
 A simple example program using the ``gettype`` function,
 ::
+
    load system type.
 
    let i = 1.
@@ -1177,6 +1211,7 @@ The `vector <https://github.com/asteroid-lang/asteroid/blob/master/asteroid/modu
 
 Here is a simple example program for the ``vector`` module,
 ::
+
    load system io.
    load system vector.
 
@@ -1236,7 +1271,7 @@ as an argument.  Let's test drive this in the Python interactive shell,
 ::
     ubuntu$ python3
     Python 3.8.10 (default, Nov 26 2021, 20:14:08)
-    [GCC 9.3.0] on 1
+    [GCC 9.3.0] on linux
     Type "help", "copyright", "credits" or "license" for more information.
     >>> from asteroid.interp import interp
     >>> interp('load system io. io @println "Hello, World!".')
@@ -1469,3 +1504,4 @@ tag we can embed Pandas functionality into Asteroid.  As an additional step we c
 wrap these individual functions into a ``structure`` with the dataframe as
 a data member and the functions as member functions of that structure.  As an
 example of this approach see the `dataframe.ast <https://github.com/asteroid-lang/asteroid/blob/master/asteroid/modules/dataframe.ast>`_ system module.
+
diff --git a/docs/Reference Guide.txt b/docs/Reference Guide.txt
index 8851b7cc..e05b2225 100644
--- a/docs/Reference Guide.txt
+++ b/docs/Reference Guide.txt
@@ -422,7 +422,7 @@ we are dealing with a list,
 ::
       let [h | t] = [1,2,3].
 
-The ``is`` Predicate
+The Is Predicate
 %%%%%%%%%%%%%%%%%%%%
 
 Syntax: ``exp IS pattern``
@@ -443,7 +443,7 @@ Example,
          io @println "not matched".
       end
 
-The ``in`` Predicate
+The In Predicate
 %%%%%%%%%%%%%%%%%%%%
 
 Syntax: ``exp IN list_exp``
@@ -515,7 +515,7 @@ First-Class Patterns
 %%%%%%%%%%%%%%%%%%%%
 
 | Syntax: ``PATTERN exp``
-| Syntax: ``* exp``
+| Syntax: ``'*' exp (BIND '[' ID (AS ID)? (',' ID (AS ID)?)*']')?``
 
 This construction allows the user to construct a pattern as a value using
 the ``pattern`` keyword.  The advantage of patterns as values is that they
@@ -534,6 +534,21 @@ variables, e.g.
 Here the pair ``(1,2)`` is matched against the pattern stored in the variable ``p``
 such that ``x`` is bound to the value ``2``.
 
+The optional ``bind`` term together with an appropriate list of variable names 
+allows the user to selectively project variable bindings from a constraint pattern 
+into the current scope.  The ``as`` keyword allows you to rename those bindings.
+Consider the following program,
+::
+      let Pair = pattern %[(x,y)]%.
+
+      -- bindings of the variables x and y are now visible as a and y respetively
+      let *Pair bind [x as a, y] = (1,2).  
+      assert( a == 1).
+      assert(y == 2).
+
+At the second  ``let`` statement we bind the ``x`` as ``a`` and ``y`` from the hidden scope 
+of the constraint pattern into our current scope.
+
 Type Patterns
 %%%%%%%%%%%%%
 
@@ -553,8 +568,8 @@ Named Patterns
 Syntax: ``name_exp ':' pattern``
 
 Named patterns allow you to bind the term matched by the pattern to a variable.
-Here the name expression has to evaluate to something that looks like a variable,
-object member variable, or array location.
+Here the name expression has to evaluate to either a variable,
+object member variable, or list location.
 
 Example,
 ::
@@ -563,6 +578,15 @@ Example,
 The variable ``x`` will be bound to the value of ``val`` if that value matches the
 type pattern ``%integer``.
 
+Named patterns are a syntactic short hand for the equivalent conditional pattern,
+::
+      name_exp if name_exp is pattern
+
+That means the following two ``let`` statements are equivalent,
+::
+      let x:(q,p) = (1,2).
+      let x if x is (q,p) = (1,2).
+
 Conditional Patterns
 %%%%%%%%%%%%%%%%%%%%
 
diff --git a/docs/User Guide.rst b/docs/User Guide.rst
index 6c82f3d8..c7326e8b 100644
--- a/docs/User Guide.rst
+++ b/docs/User Guide.rst
@@ -2,20 +2,11 @@
 
 
 
-
-
-
-
-
-
-
-
-
-
 ..
    *** DO NOT EDIT; MACHINE GENERATED ***
 
 
+
 .. highlight:: none
 
 Asteroid User Guide
@@ -33,12 +24,16 @@ paradigm.  Here are just two examples:
 
 **Example:** All statements that look like assignments are actually pattern-match statements.  For example if we state,
 ::
+
     let [x,2,y] = [1,2,3].
 
+
 that means the subject term ``[1,2,3]`` is matched to the pattern ``[x,2,y]`` and ``x`` and ``y`` are bound to the values 1 and 3, respectively.  By the way, there is nothing wrong with the following statement,
 ::
+
     let [1,2,3] = [1,2,3].
 
+
 which is just another pattern match without any variable instantiations.
 
 **Example:** Patterns in Asteroid are first-class citizens of the language.
@@ -46,6 +41,7 @@ This is best demonstrated with a program.  Here is a program
 that recursively computes the factorial of a positive integer and uses first-class patterns
 in order to ensure that the domain of the function is not violated,
 ::
+
     -- define first-class patterns
     let POS_INT = pattern (x:%integer) if x > 0.
     let NEG_INT = pattern (x:%integer) if x < 0.
@@ -60,6 +56,7 @@ in order to ensure that the domain of the function is not violated,
             throw Error("undefined for "+n).
         end
 
+
 As you can see, the program first creates patterns and stores them in the variables
 ``POS_INT`` and ``NEG_INT`` and it uses those patterns later in the code by
 dereferencing those variables with the ``*`` operator.  First-class patterns have
@@ -88,8 +85,10 @@ Asteroid arranges these data types in a **type hierarchy**,
 Type hierarchies facilitate automatic type promotion.  Here is an example
 where automatic type promotion is used to put together a string from different data types,
 ::
+
     let x:%string = "value: " + 1.
 
+
 Here we associate the string ``"value: 1"`` with the variable ``x`` by first promoting the integer value ``1`` to the string ``"1"`` using the fact that ``integer`` < ``string``  according to our type hierarchy  and then interpreting the ``+`` operator as a string concatenation operator.
 
 Asteroid supports two more data types:
@@ -100,13 +99,17 @@ Asteroid supports two more data types:
 These are **structured data types** in that they can contain entities that belong to other data types. Both of these data types have constructors which are possibly empty sequences of comma separated values enclosed by square brackets for lists, e.g. ``[1,2,3]``, and enclosed by parentheses for tuples, e.g. ``(x,y)``. For tuples we have the caveat that the 1-tuple is represented by a value followed by a comma to distinguish it from parenthesized expressions, e.g. ``(3,)``.
 Here are some examples,
 ::
+
     let l = [1,2,3].  -- this is a list
     let t = (1,2,3).  -- this is a tuple
 
+
 As we said above, in order to distinguish it from a parenthesized value the single element in a 1-tuple has to be followed by a comma, like so,
 ::
+
     let one_tuple = (1,).  -- this is a 1-tuple
 
+
 Lists and tuples themselves are also embedded in type hierarchies, although very simple ones:
 
 * ``list`` < ``string``
@@ -114,19 +117,23 @@ Lists and tuples themselves are also embedded in type hierarchies, although very
 
 That is, any list or tuple can be viewed as a string.  This is very convenient for printing lists and tuples,
 ::
+
     load system io.
     io @println ("this is my list: " + [1,2,3]).
 
 
+
 Finally, Asteroid supports one more type, namely the ``none`` type.  The ``none`` type has
 only one member: A constant named ``none``.  However, it turns out that the null-tuple, a tuple with no components
 indicated by ``()``, also belongs to this type rather than the tuple type discussed earlier. But the ``none``
 data type only has one constant, this implies that ``()`` and ``none`` mean the same thing and can be used
 interchangeably.  That is, the following ``let`` statements will succeed,
 ::
+
     let none = ().
     let () = none.
 
+
 showing that ``()`` and ``none`` are equivalent and pattern-match each other.
 The ``none`` data type itself does not belong to any type hierarchy.
 
@@ -141,31 +148,37 @@ Lists
 In Asteroid the ``list`` is a fundamental, built-in data structure.  A trait it shares with programming languages such as Lisp, Python, ML, and Prolog.  Below is a list reversal example program.  Notice that lists are zero-indexed and
 elements of a list are accessed via the ``@`` operator,
 ::
+
     load system io.    -- load the io module so we can print
 
     let a = [1,2,3].             -- construct list a
     let b = [a @2, a @1, a @0].  -- reverse list a
     io @println b.
 
+
 The output is: ``[3,2,1]``.
 
 We can achieve the same effect by giving a list of index values (a slice) to the ``@`` operator,
 ::
+
     load system io.    -- load the io module so we can print
 
     let a = [1,2,3].     -- construct list a
     let b = a @[2,1,0].  -- reverse list a using slice [2,1,0]
     io @println b.
 
+
 In Asteroid lists are considered objects with member functions that can manipulate list
 objects. We could rewrite the above example as,
 ::
+
     load system io.
 
     let a = [1,2,3].
     let b = a @reverse(). -- reverse list using member function 'reverse'
     io @println b.
 
+
 The ``@`` operator allows you to access either individual elements, slices, or member functions of a list.
 Actually, the ``@`` operator is more general than that, it is Asteroid's substructure access operator.
 Notice that in order to access the ``println`` function of the ``io`` module we also use the ``@`` operator.
@@ -178,6 +191,7 @@ Besides using the default constructor for lists which consists of the
 square brackets enclosing a list of elements we can use **list comprehensions** to construct lists.  In Asteroid a list comprehension consist of a range specifier together with
 a step specifier allowing you to generate integer values within that range,
 ::
+
     load system io.
 
     -- build a list of odd values
@@ -189,6 +203,7 @@ a step specifier allowing you to generate integer values within that range,
     let b = a @slice.
     io @println ("reversed list: " + b).
 
+
 The output is,
 ::
 
@@ -199,6 +214,7 @@ Asteroid's simple list comprehensions in conjunction with the ``map`` function f
 construct virtually  any kind of list. For example, the following program constructs
 a list of alternating 1 and -1,
 ::
+
     load system io.
     load system math.
 
@@ -207,6 +223,7 @@ a list of alternating 1 and -1,
 
     io @println a.
 
+
 where the output is,
 ::
 
@@ -214,6 +231,7 @@ where the output is,
 
 Higher dimensional arrays can easily be simulated with lists of lists,
 ::
+
     load system io.
 
     -- build a 2-D array
@@ -225,6 +243,7 @@ Higher dimensional arrays can easily be simulated with lists of lists,
     let b @1 @1 = 0.
     io @println ("["+b@0+"\n "+b@1+"\n "+b@2+"]").
 
+
 The output is,
 ::
     [[1,2,3]
@@ -238,12 +257,15 @@ Tuples
 As we saw earlier, the ``tuple`` is another fundamental, built-in data structure that can be found in Asteroid.
 Below is an example of a tuple declaration and access.
 ::
+
     let a = (1,2,3).    -- construct tuple a
     let b = a @1.       -- access the second element in tuple a
     assert(b == 2).     -- assert that the value of the second element is correct
 
+
 Lists and tuples may be nested,
 ::
+
     -- build a list of tuples
     let b = [("a","b","c"),
              ("d","e","f"),
@@ -251,8 +273,10 @@ Lists and tuples may be nested,
     -- Access an element in the nested structure.
     assert(b @1 @1 == "e").
 
+
 Unlike lists, tuples are immutable. This means that their contents cannot be changed once they have been declared.  The following code block demonstrates this,
 ::
+
     load system io.
 
     let b = ("a","b","c"). -- build a tuple
@@ -263,6 +287,7 @@ Unlike lists, tuples are immutable. This means that their contents cannot be cha
         io @println (kind+": "+message).
     end.
 
+
 Which will print out the following message:
 ::
 
@@ -293,6 +318,7 @@ Also, the data fields of an object are accessed via
 their names rather than index values.  Here is a simple example that illustrates
 all this,
 ::
+
     -- define a structure of type A
     structure A with
         data a.
@@ -303,8 +329,10 @@ all this,
     assert( obj @a == 1 ).  -- access first data member
     assert( obj @b == 2 ).  -- access second data member
 
+
 The following is a more involved example,
 ::
+
     load system io.
 
     structure Person with
@@ -328,6 +356,7 @@ The following is a more involved example,
     -- print out the member values
     io @println (name + " is " + age + " years old and is a " +  gender + ".").
 
+
 The output is,
 ::
 
@@ -340,8 +369,8 @@ information from a ``Person`` object.
 In addition to the default constructor, structures in Asteroid also support user specified
 constructors and member functions.  We'll talk about those later when we talk about OO programming in Asteroid.
 
-The ``let`` Statement
----------------------
+The Let Statement
+-----------------
 
 The ``let`` statement is a pattern matching statement and can be viewed as Asteroid's version of the assignment statement even though statements like,
 ::
@@ -352,18 +381,22 @@ where we take the term on the right side and match it to the pattern on the left
 the ``=`` operator are completely legal and highlight the fact that ``let`` statement is not equivalent to an assignment statement.  Simple patterns are expressions that consist purely of constructors and variables. Constructors themselves consist of constants, list and tuple constructors, and user defined structures.
 Here is an example where we do some computations on the right side of a ``let`` statement and then match the result against a pattern on the left,
 ::
+
     load system io.
 
     let [x,2,y] = [1+0,1+1,1+2].
     io @println (x,y).
 
+
 The output is: ``(1,3)``
 
 Asteroid supports special patterns called **type patterns** that match any value
 of a given type.  For instance, the ``%integer`` pattern matches any integer value.  Here is a simple example,
 ::
+
     let %integer = 1.
 
+
 This ``let`` statement succeeds because ``1`` is an integer value can be pattern-matched against
 the type pattern ``%integer``.
 
@@ -372,11 +405,13 @@ supports something called a **named pattern** were a (sub)pattern on the left si
 of a ``let`` statement (or any pattern as it appears in Asteroid) can be given a name
 and that name will be instantiated with a term during pattern matching.  For example,
 ::
+
     load system io.
 
     let t:(1,2) = (1,2).  -- using a named pattern on lhs
     io @println t.
 
+
 Here, the construct ``t:(1,2)`` is called a named pattern and the variable ``t`` will be unified with the term ``(1,2)``, or more generally, the variable will be unified with term
 that matches the pattern on the right of the colon.  The program will print,
 ::
@@ -387,6 +422,7 @@ We can combine type patterns and named patterns to give us something that looks
 like a variable declaration in other languages. In Asteroid, though, it is still just all
 about pattern matching.  Consider,
 ::
+
     load system io.
     load system math.
     load system type.
@@ -394,6 +430,7 @@ about pattern matching.  Consider,
     let x:%real = math @pi.
     io @println (type @tostring (x,type @stringformat (4,2))).
 
+
 The left side of the ``let`` statement is a named type pattern that matches any real value, and
 if that match is successful then the value is bound to the variable ``x``.  Note
 that even though this looks like a declaration, it is in fact a pattern matching
@@ -407,12 +444,14 @@ Control structure implementation in Asteroid is along the lines of any of the mo
 
 As we said, in terms of flow of control statements there are really not a lot of surprises. This is because Asteroid supports loops and conditionals in a very similar way to many of the other modern programming languages.  For example, here is a short program with a ``for`` loop that prints out the first six even positive integers,
 ::
+
     load system io.
 
     for i in 0 to 10 step 2 do
         io @println i.
     end
 
+
 The output is,
 ::
 
@@ -425,6 +464,7 @@ The output is,
 
 Here is another example that iterates over lists,
 ::
+
     load system io.
     load system util
 
@@ -432,6 +472,7 @@ Here is another example that iterates over lists,
         io @println ("the "+ix+" bird is a "+bird).
     end
 
+
 The output is,
 ::
 
@@ -444,6 +485,7 @@ iterate pattern matching on each of the pairs on the list with the pattern ``(ix
 
 The following is a short program that demonstrates an ``if`` statement,
 ::
+
     load system io.
     load system type.
 
@@ -460,6 +502,7 @@ The following is a short program that demonstrates an ``if`` statement,
         io @println "Something else".
     end
 
+
 Even though Asteroid's flow of control statements look so familiar, they support pattern matching to a degree not found in other programming languages and which we will take a look at below.
 
 Functions
@@ -469,6 +512,7 @@ Functions in Asteroid resemble function definitions in functional programming la
 Here functions have a single formal argument and function calls are expressed via juxtaposition
 of the function name and the actual argument.  Here is a simple example,
 ::
+
     function double
         with i do -- pattern match the actual arg with i
             return 2*i.
@@ -477,6 +521,7 @@ of the function name and the actual argument.  Here is a simple example,
     let d = double 2.  -- function call via juxtaposition
     assert( d == 4 ).
 
+
 In the ``with`` statement we pattern match the actual argument that is
 being passed in against the variable ``i``.  Also note that the function call is expressed via juxtaposition,
 no parentheses necessary.
@@ -484,6 +529,7 @@ no parentheses necessary.
 If we wanted to pass more than a single value to a function we have to create
 a tuple and then pass that tuple to the function like in this example,
 ::
+
     function reduce
         with (a,b) do -- pattern match the actual argument
             return a*b.
@@ -492,6 +538,7 @@ a tuple and then pass that tuple to the function like in this example,
     let r = reduce (2,4).  -- function call via juxtaposition
     assert( r == 8 ).
 
+
 Even though the function call looks like a traditional function call like in
 Python it is not.  The underlying mechanism is quite different: on the call site
 we construct a tuple that holds all our values which is then passed to the function as the only parameter.
@@ -505,6 +552,7 @@ The following is the quick sort implemented in
 Asteroid where each ``with`` clause introduces a new function body with its
 corresponding pattern,
 ::
+
     load system io.
 
     function qsort
@@ -530,6 +578,7 @@ corresponding pattern,
     -- print the sorted list
     io @println (qsort [3,2,1,0])
 
+
 The output is as expected,
 ::
 
@@ -546,10 +595,12 @@ As you have seen in a couple of occasions already in the document, Asteroid also
 functions except that you declare them on-the-fly and they are declared without a
 name.  Here is an example using a ``lambda`` function,
 ::
+
     load system io.
 
     io @println ((lambda with n do return n+1) 1).
 
+
 The output is ``2``.  Here, the lambda function is a function that takes a value
 and increments it by one.  We then apply the value ``1`` to the function and the
 print function prints out the value ``2``.
@@ -560,11 +611,12 @@ Pattern Matching
 Pattern matching lies at the heart of Asteroid.  We saw some of Asteroid's pattern matching ability when we discussed the ``let`` statement.  We can also have pattern matching
 in expressions using the ``is`` predicate.
 
-Pattern Matching in Expressions: The ``is`` Predicate
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+Pattern Matching in Expressions: The Is Predicate
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 Consider the following example of this predicate among some patterns,
 ::
+
     load system io.
 
     let p = (1,2).
@@ -577,6 +629,7 @@ Consider the following example of this predicate among some patterns,
         io @println "it's something else".
     end
 
+
 Here we use patterns to determine if ``p`` is a triple, a pair, or something else. Pattern matching is embedded in the expressions of the ``if`` statement using the ``is`` predicate. The
 output of this program is,
 ::
@@ -599,6 +652,7 @@ We can also employ pattern matching in loops.
 In the following program we use the ``is`` predicate to test whether a list is empty or not
 while looping,
 ::
+
     load system io.
 
     let list = [1,2,3].
@@ -609,6 +663,7 @@ while looping,
         let list = tail.
     until list is []. -- pattern match with is predicate
 
+
 The output is,
 ::
 
@@ -633,6 +688,7 @@ Here ``x`` and ``y`` are variables, ``0`` represents the natural number with val
 the Peano arithmetic based on the two axiom where we replaced the ``+`` operator with the
 ``add`` symbol,
 ::
+
     -- implements Peano addition on terms
     load system io.
 
@@ -657,6 +713,7 @@ the Peano arithmetic based on the two axiom where we replaced the ``+`` operator
     -- add 2 3
     io @println (reduce(add(s(s(0)),s(s(s(0)))))).
 
+
 Our program defines the structure ``s`` to represent the successor function and the structure ``add`` to represent Peano addition. Next, it defines a function that uses pattern matching to identify the left sides of the two axioms.  If either pattern matches the input to the ``reduce`` function, it will activate the corresponding function body and rewrite the term recursively in an appropriate manner.  We have one additional pattern which matches if neither one of the Peano axiom patterns matches and terminates the recursion.  Finally,  on the last line, we use our ``reduce`` function to compute the Peano term for the addition of 2 + 3. As expected, the output of this program is,
 ::
 
@@ -673,6 +730,7 @@ input values to function bodies.  Consider the following definition of the
 ``factorial`` function where we use conditional pattern matching to control
 the kind of values that are being passed to a particular function body,
 ::
+
     load system io.
 
     function factorial
@@ -686,19 +744,21 @@ the kind of values that are being passed to a particular function body,
 
     io @println ("The factorial of 3 is: " + factorial 3).
 
+
 Here we see that first, we make sure that we are being passed integers and second,
 that the integers are positive using the appropriate conditions on the input values. If
 we are being passed a negative integer, then we throw an error.
 
 
-Pattern Matching in ``for`` Loops
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+Pattern Matching in For Loops
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 We have seen pattern matching in ``for`` loops earlier.  Here we show another
 example. This combines structural matching with regular expression matching
 in ``for`` loops
 that selects certain items from a list. Suppose we want to print out the names of persons that contain a lower case 'p',
 ::
+
     load system io.
 
     structure Person with
@@ -718,13 +778,15 @@ that selects certain items from a list. Suppose we want to print out the names o
         io @println name.
     end
 
+
 Here we pattern match the ``Person`` object in the ``for`` loop and then use a regular expression to see if the name of that person matches our requirement that it contains a lower case 'p'.  We can tag the pattern with a variable name, a named pattern, so that we can print out the name if the regular expression matches. The output is ``Sophie``.
 
-Pattern Matching in ``try-catch`` Statements
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+Pattern Matching in Try-Catch Statements
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 Exception handling in Asteroid is very similar to exception handling in many of the other modern programming languages available today.  The example below shows an Asteroid program  that throws one of two exceptions depending on the randomly generated value ``i``,
 ::
+
     load system io.
     load system random.
     load system type.
@@ -750,6 +812,7 @@ Exception handling in Asteroid is very similar to exception handling in many of
         io @println("you loose with "+type @tostring(v,type @stringformat(4,2))).
     end
 
+
 The ``Head`` and ``Tail`` exceptions are handled by their corresponding ``catch`` statements, respectively.  In both cases the exception object is unpacked using pattern matching and the unpacked value is used in the appropriate message printed to the screen.
 
 It is worth noting that even though Asteroid has builtin exception objects such as ``Error``,
@@ -780,6 +843,7 @@ The right side of the ``let`` statement invokes the default constructor for the
 structure in order to create an instance stored in the variable ``scarlett``. We
 can access members of the instance,
 ::
+
     load system io.
 
     structure Person with
@@ -792,12 +856,14 @@ can access members of the instance,
     -- access the name field of the structure instance
     io @println (scarlett @name).
 
+
 Asteroid allows you to attach functions to structures.  In member functions
 the object identity of the instance is available through the ``this`` keyword.
 For example, we can
 extend our ``Person`` structure with the ``hello`` function that uses the ``name`` field
 of the instance,
 ::
+
     load system io.
 
     structure Person with
@@ -814,6 +880,7 @@ of the instance,
     -- call the member function
     scarlett @hello().
 
+
 This program will print out,
 ::
 
@@ -827,6 +894,7 @@ The only thing you need to keep in mind is that you **cannot** pattern match on
 function field.  From a pattern matching perspective, a structure consists only of
 data fields.  So even if we declare a structure like this,
 ::
+
     load system io.
 
     structure Person with
@@ -844,6 +912,7 @@ data fields.  So even if we declare a structure like this,
     let Person(name,age,_) = Person("Scarlett",28,"F").
     io @println (name+" is "+age+" years old").
 
+
 where the function ``hello`` is defined in the middle of the data fields,
 pattern matching simply ignores the function definition and pattern matches
 only on the data fields.  The output of the program is,
@@ -859,6 +928,7 @@ dog instance by calling the ``add_trick`` function.  Rather than using the defau
 constructor, we define a constructor for our instances with the ``__init__`` function.
 Here is the program listing for the example in Asteroid,
 ::
+
     load system io.
     load system type.
 
@@ -893,6 +963,7 @@ Here is the program listing for the example in Asteroid,
         io @println (name+" knows how to fetch").
     end
 
+
 After declaring the structure we instantiate two dogs, Fido and Buddy, and add
 tricks to their respective trick repertoires.  The last couple of lines
 of the program consist of a ``for`` loop over a list of our dogs.
@@ -992,6 +1063,7 @@ in many spots in a program.  If patterns are not first-class citizens the develo
 will have to retype the same patterns over and over again in the various different
 spots where the patterns occurs. Consider the following program snippet,
 ::
+
     function fact
         with 0 do
             return 1
@@ -1010,10 +1082,12 @@ spots where the patterns occurs. Consider the following program snippet,
             return -1.
         end
 
+
 In order to write these two functions we had to repeat the almost identical pattern
 four times.  First-class patterns allow us to write the same two functions in a
 much more elegant way,
 ::
+
     let POS_INT = pattern (x:%integer) if x > 0.
     let NEG_INT = pattern (x:%integer) if x < 0.
 
@@ -1035,6 +1109,7 @@ much more elegant way,
                 return -1.
             end
 
+
 The relevant patterns are now stored in the variables ``POS_INT`` and ``NEG_INT``
 which are then used in the function definitions.
 
@@ -1064,6 +1139,7 @@ into the current environment.
 The most common use of constraint patterns is the prevention of non-linear patterns
 in functions.  Consider the following program,
 ::
+
    load system io.
 
    let POS_INT = pattern %[v if (v is %integer) and v > 0]%.
@@ -1082,6 +1158,39 @@ With the ``%[...]%`` operators in place we prevent
 the pattern ``v if (v is %integer) and v > 0`` from instantiating the variable ``v`` thus preventing a non-linearity
 to occur in the argument list pattern.
 
+Sometimes we need to use constraint patterns instead of straightforward patterns
+in order to avoid non-linearities but
+we also want controlled access to the variables these constraint patterns declare.
+We achieve this by using the ``bind`` keyword at the pattern-match site.  
+Consider the following program,
+::
+
+   -- declare a pattern that matches scalar values
+   let Scalar = pattern %[p if (p is %integer) or (p is %real)]%.
+
+   -- declare a pattern that matches pairs of scalars
+   let Pair = pattern %[(x:*Scalar,y:*Scalar)]%.
+
+   -- compute the dot product of two pairs of scalars
+   function dot2d 
+      with (*Pair bind [x as a1, y as a2], *Pair bind [x as b1, y as b2]) do
+         a1*b1 + a2*b2
+   end
+
+   assert(dot2d((1,0),(0,1)) == 0).
+
+In the function definition of ``dot2d`` we see that the ``Pair`` pattern is used 
+twice to make sure that the function is called with a pair of pairs as its argument.
+However, in order to compute the dot product of those two pairs we need access 
+to the values each pair matched.  We use the ``bind`` keyword together with an 
+appropriate binding term list to extract the matched values.  For the first
+pair we map ``x`` and ``y`` to ``a1`` and ``a2`` and for the second 
+pair we map ``x`` and ``y`` to ``b1`` and ``b2``, respectively.
+
+As a quick aside, the ``as`` construction in the binding term list is only necessary 
+when trying to resolve non-linearities otherwise the binding term list can just consist
+of the variable names appearing in the pattern that you want to bind into the current
+scope.
 
 More on Multi-Dispatch
 ----------------------
@@ -1095,6 +1204,7 @@ In order to demonstrate this type of multi-dispatch, we show the example program
 `multi-dispatch Wikipedia page <https://en.wikipedia.org/wiki/Multiple_dispatch>`_
 written in Asteroid,
 ::
+
     load system io.
     load system type.
 
@@ -1142,6 +1252,7 @@ written in Asteroid,
     io @println (collide(Asteroid(10), Spaceship(10))).
     io @println (collide(Spaceship(101), Spaceship(10))).
 
+
 Each ``with`` clause in the function ``collide_with`` introduces a new function body with its
 corresponding pattern.
 The function bodies in this case are simple ``return`` statements
@@ -1186,6 +1297,7 @@ The ``kind`` field will be populated by Asteroid with one of the following strin
 In addition to the ``kind`` field, the ``value`` field holds a string with some further details on the exception. Specific exceptions can be caught by pattern matching on the ``kind`` field of the ``Exception`` object.  For
 example,
 ::
+
     load system io.
 
     try
@@ -1194,6 +1306,7 @@ example,
         io @println s.
     end
 
+
 The output is,
 ::
 
@@ -1202,6 +1315,7 @@ The output is,
 
 Asteroid also provides a predefined ``Error`` object for user level exceptions,
 ::
+
     load system io.
 
     try
@@ -1210,9 +1324,11 @@ Asteroid also provides a predefined ``Error`` object for user level exceptions,
         io @println s.
     end
 
+
 Of course the user can also use the ``Exception`` object for their own exceptions
 by defining a ``kind`` that does not interfere with the predefined ``kind`` strings above,
 ::
+
     load system io.
 
     try
@@ -1221,6 +1337,7 @@ by defining a ``kind`` that does not interfere with the predefined ``kind`` stri
         io @println s.
     end
 
+
 The output here is,
 ::
 
@@ -1229,6 +1346,7 @@ The output here is,
 In addition to the Asteroid defined exceptions,
 the user is allowed to construct user level exceptions with any kind of object including tuples and lists. Here is an example that constructs a tuple as an exception object,
 ::
+
     load system io.
 
     try
@@ -1237,11 +1355,13 @@ the user is allowed to construct user level exceptions with any kind of object i
         io @println v.
     end
 
+
 The output of this program is ``42``.
 
 Now, if you don't care what kind of exception you catch, you need to use a ``wildcard`` or a variable because exception handlers are activated via pattern matching on the
 exception object itself.  Here is an example using a ``wildcard``,
 ::
+
     load system io.
 
     try
@@ -1250,8 +1370,10 @@ exception object itself.  Here is an example using a ``wildcard``,
         io @println "something happened".
     end
 
+
 Here is an example using a variable,
 ::
+
     load system io.
     load system type.
 
@@ -1261,6 +1383,7 @@ Here is an example using a variable,
         io @println ("something happened: "+type @tostring(e)).
     end
 
+
 In this last example we simply convert the caught exception object into a string
 and print it,
 ::
@@ -1274,12 +1397,14 @@ Basic Asteroid I/O
 
 I/O functions are defined as member functions of the ``io`` module. The ``println`` function prints its argument in a readable form to the terminal.  Recall that the ``+`` operator also implements string concatenation.  This allows us to construct nicely formatted output strings,
 ::
+
     load system io.
 
     let a = 1.
     let b = 2.
     io @println ("a + b = " + (a + b)).
 
+
 The output is
 ::
 
@@ -1295,6 +1420,7 @@ The width specifier tells the ``tostring`` function how many characters to reser
 
 Here is a program that exercises some of the string formatting options,
 ::
+
     load system io.
     load system type.
     load system math.
@@ -1316,6 +1442,7 @@ Here is a program that exercises some of the string formatting options,
     let r = type @tostring(math @pi,type @stringformat(6,3)).
     io @println r.
 
+
 The output of the program is,
 ::
 
@@ -1331,11 +1458,13 @@ except that it does not terminate print with a newline.
 
 Another useful function defined in the ``io`` module is the ``input`` function that, given an optional prompt string, will prompt the user at the terminal and return the input value as a string.  Here is a small example,
 ::
+
     load system io.
 
     let name = io @input("What is your name? ").
     io @println ("Hello " + name + "!").
 
+
 The output is,
 ::
 
@@ -1346,6 +1475,7 @@ The output is,
 We can use the type casting functions such as ``tointeger`` or ``toreal`` defined in the
 ``type`` module to convert the string returned from ``input`` into a numeric value,
 ::
+
     load system io.
     load system type.
 
@@ -1355,6 +1485,7 @@ We can use the type casting functions such as ``tointeger`` or ``toreal`` define
         io @println k.
     end
 
+
 The output is,
 ::
 
@@ -1392,12 +1523,15 @@ rather than in user directories.
 
 Say that you wanted to load the ``math`` module so you could execute a certain trigonometric function. The following Asteroid program loads the ``math`` module as well as the ``io``  module. Only after loading them would you be able to complete the sine function below,
 ::
+
     load system io.
     load system math.
 
     let x = math @sin( math @pi / 2 ).
     io @println("The sine of pi / 2 is " + x + ".").
 
+
 Both the function ``sin`` and the constant value ``pi`` are defined in the ``math`` module.
 In addition, the ``io`` module is where all input/output functions in Asteroid (such as ``println``) come from.
 If you want the complete list of modules, make sure to check out the reference guide `here <https://asteroid-lang.readthedocs.io/en/latest/Reference%20Guide.html>`_.
+
diff --git a/docs/User Guide.txt b/docs/User Guide.txt
index 8d3ce99b..42c837bc 100644
--- a/docs/User Guide.txt
+++ b/docs/User Guide.txt
@@ -238,8 +238,8 @@ information from a ``Person`` object.
 In addition to the default constructor, structures in Asteroid also support user specified
 constructors and member functions.  We'll talk about those later when we talk about OO programming in Asteroid.
 
-The ``let`` Statement
----------------------
+The Let Statement
+-----------------
 
 The ``let`` statement is a pattern matching statement and can be viewed as Asteroid's version of the assignment statement even though statements like,
 ::
@@ -387,8 +387,8 @@ Pattern Matching
 Pattern matching lies at the heart of Asteroid.  We saw some of Asteroid's pattern matching ability when we discussed the ``let`` statement.  We can also have pattern matching
 in expressions using the ``is`` predicate.
 
-Pattern Matching in Expressions: The ``is`` Predicate
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+Pattern Matching in Expressions: The Is Predicate
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 Consider the following example of this predicate among some patterns,
 ::
@@ -467,8 +467,8 @@ that the integers are positive using the appropriate conditions on the input val
 we are being passed a negative integer, then we throw an error.
 
 
-Pattern Matching in ``for`` Loops
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+Pattern Matching in For Loops
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 We have seen pattern matching in ``for`` loops earlier.  Here we show another
 example. This combines structural matching with regular expression matching
@@ -479,8 +479,8 @@ that selects certain items from a list. Suppose we want to print out the names o
 
 Here we pattern match the ``Person`` object in the ``for`` loop and then use a regular expression to see if the name of that person matches our requirement that it contains a lower case 'p'.  We can tag the pattern with a variable name, a named pattern, so that we can print out the name if the regular expression matches. The output is ``Sophie``.
 
-Pattern Matching in ``try-catch`` Statements
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+Pattern Matching in Try-Catch Statements
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 Exception handling in Asteroid is very similar to exception handling in many of the other modern programming languages available today.  The example below shows an Asteroid program  that throws one of two exceptions depending on the randomly generated value ``i``,
 ::
@@ -704,6 +704,26 @@ With the ``%[...]%`` operators in place we prevent
 the pattern ``v if (v is %integer) and v > 0`` from instantiating the variable ``v`` thus preventing a non-linearity
 to occur in the argument list pattern.
 
+Sometimes we need to use constraint patterns instead of straightforward patterns
+in order to avoid non-linearities but
+we also want controlled access to the variables these constraint patterns declare.
+We achieve this by using the ``bind`` keyword at the pattern-match site.  
+Consider the following program,
+::
+#include "../asteroid/test-suites/ug-programs/prgm-043a.ast"
+
+In the function definition of ``dot2d`` we see that the ``Pair`` pattern is used 
+twice to make sure that the function is called with a pair of pairs as its argument.
+However, in order to compute the dot product of those two pairs we need access 
+to the values each pair matched.  We use the ``bind`` keyword together with an 
+appropriate binding term list to extract the matched values.  For the first
+pair we map ``x`` and ``y`` to ``a1`` and ``a2`` and for the second 
+pair we map ``x`` and ``y`` to ``b1`` and ``b2``, respectively.
+
+As a quick aside, the ``as`` construction in the binding term list is only necessary 
+when trying to resolve non-linearities otherwise the binding term list can just consist
+of the variable names appearing in the pattern that you want to bind into the current
+scope.
 
 More on Multi-Dispatch
 ----------------------
diff --git a/editor-support/asteroid.vim b/editor-support/asteroid.vim
index 49a4bc83..c5327efe 100644
--- a/editor-support/asteroid.vim
+++ b/editor-support/asteroid.vim
@@ -11,9 +11,45 @@ if exists("b:current_syntax")
 	finish
 endif
 
-syn keyword basic with end do load let for function structure in is pattern 
-syn keyword basic throw this system data global return to step if not
-syn keyword basic else or and
+syn keyword basic and
+syn keyword basic as
+syn keyword basic assert
+syn keyword basic bind
+syn keyword basic break
+syn keyword basic catch
+syn keyword basic data
+syn keyword basic do
+syn keyword basic elif
+syn keyword basic else
+syn keyword basic end
+syn keyword basic escape
+syn keyword basic eval
+syn keyword basic for
+syn keyword basic from
+syn keyword basic function
+syn keyword basic global
+syn keyword basic if
+syn keyword basic in
+syn keyword basic is
+syn keyword basic lambda
+syn keyword basic let
+syn keyword basic load
+syn keyword basic loop
+syn keyword basic not
+syn keyword basic or
+syn keyword basic orwith
+syn keyword basic pattern
+syn keyword basic repeat
+syn keyword basic return
+syn keyword basic step
+syn keyword basic structure
+syn keyword basic system
+syn keyword basic throw
+syn keyword basic to
+syn keyword basic try
+syn keyword basic until
+syn keyword basic while
+syn keyword basic with
 
 syn keyword delimeter escape
 
diff --git a/editor-support/vscode/syntaxes/asteroid.tmLanguage.json b/editor-support/vscode/syntaxes/asteroid.tmLanguage.json
index 8f68d8f9..4d51b2a2 100644
--- a/editor-support/vscode/syntaxes/asteroid.tmLanguage.json
+++ b/editor-support/vscode/syntaxes/asteroid.tmLanguage.json
@@ -90,7 +90,7 @@
 		{
 			"name": "keyword",
 			"comment": "keyword.other.asteroid",
-			"match": "\\b(assert|eval)\\b"
+			"match": "\\b(as|assert|bind|eval)\\b"
 		},
 		{
 			"name": "keyword.operator.comparison.asteroid",


Test patch:
diff --git a/asteroid/test-suites/regression-tests/test008.ast b/asteroid/test-suites/regression-tests/test008.ast-not-valid
similarity index 64%
rename from asteroid/test-suites/regression-tests/test008.ast
rename to asteroid/test-suites/regression-tests/test008.ast-not-valid
index 71b82127..916061c2 100644
--- a/asteroid/test-suites/regression-tests/test008.ast
+++ b/asteroid/test-suites/regression-tests/test008.ast-not-valid
@@ -1,3 +1,6 @@
+-- this test case is no longer valid, we no longer allow
+-- patterns as constructors, except for the simplest
+-- cases because patterns have become too complicated
 load system io.
 
 structure Family with
@@ -10,7 +13,7 @@ structure Family with
     end
   end -- structure
   
-let FAMILY = pattern with Family(*PARENT1).
+let FAMILY = pattern with Family(PARENT1).
 
 structure Parent with
   data name.
diff --git a/asteroid/test-suites/regression-tests/test139.ast b/asteroid/test-suites/regression-tests/test139.ast
new file mode 100644
index 00000000..8fe0825b
--- /dev/null
+++ b/asteroid/test-suites/regression-tests/test139.ast
@@ -0,0 +1,9 @@
+-- test binding terms
+let Pair = pattern %[(x,y)]%.
+
+function add with ( *Pair bind [x as a, y as b], 
+                    *Pair bind [x as c, y as d] ) do
+   return (a+c, b+d).
+end 
+
+assert(add((1,2),(3,4))== (4,6)).
\ No newline at end of file
diff --git a/asteroid/test-suites/regression-tests/test140.ast b/asteroid/test-suites/regression-tests/test140.ast
new file mode 100644
index 00000000..59a89303
--- /dev/null
+++ b/asteroid/test-suites/regression-tests/test140.ast
@@ -0,0 +1,6 @@
+-- test binding terms
+let Pair = pattern %[(x,y)]%.
+
+let *Pair bind [x as a, y] = (1,2).  -- bindings of the variables x and y are now visible again
+assert( a == 1).
+assert(y == 2).
diff --git a/asteroid/test-suites/regression-tests/test141.ast b/asteroid/test-suites/regression-tests/test141.ast
new file mode 100644
index 00000000..24665d96
--- /dev/null
+++ b/asteroid/test-suites/regression-tests/test141.ast
@@ -0,0 +1,7 @@
+let Pair = pattern (x,y).
+
+try 
+   let *Pair bind [x as a, y] = (1,2).  -- bindings of the variables x and y are now visible again
+catch Exception(errortype,s) do
+   assert(s is ".*binding term lists.*").
+end
diff --git a/asteroid/test-suites/ug-programs/prgm-043a.ast b/asteroid/test-suites/ug-programs/prgm-043a.ast
new file mode 100644
index 00000000..20c09726
--- /dev/null
+++ b/asteroid/test-suites/ug-programs/prgm-043a.ast
@@ -0,0 +1,13 @@
+   -- declare a pattern that matches scalar values
+   let Scalar = pattern %[p if (p is %integer) or (p is %real)]%.
+
+   -- declare a pattern that matches pairs of scalars
+   let Pair = pattern %[(x:*Scalar,y:*Scalar)]%.
+
+   -- compute the dot product of two pairs of scalars
+   function dot2d 
+      with (*Pair bind [x as a1, y as a2], *Pair bind [x as b1, y as b2]) do
+         a1*b1 + a2*b2
+   end
+
+   assert(dot2d((1,0),(0,1)) == 0).
\ No newline at end of file