CS 8113g Spring 1995

Specification and analysis of interactive systems

CS 8113g Spring 1995

Lecture 4: A Tutorial in Z (con'd)

Date: April 6, 1995
Scribe: Colleen Kehoe


Sequences

Notation

Finite Functions

A function is finite if its domain is a finite set. For example a function whose domain is N is not finite. A function whose domain is the set of integers between 1 and 10, is finite.

Sequences

We are thinking of sequences as functions:
	seq X == {f:N -||-> X | dom f = 1..#f}
A sequence over X is a finite partial function (f) from the integers into X such that the domain of f is the interval between 1 and the size of the function. An example to illustrate the restriction on the domain:
	A Sequence		Not A Sequence

	1 -> x			5 -> x
	2 -> y			3 -> y
	3 -> a			8 -> a
	4 -> d			2 -> d

Sets vs. Sequences

Indexing

We can refer to a particular element of a sequence through indexing. This is the same idea used to access a particular element of an array in a programming language. To access the ith element of sequence (array) s:
	<s>i == s[i]
Q. What is <s>0?
A. The index (in this case 0) must be in the domain of the function. Therefore, this is an invalid statement. The index must be in the interval 1..#f.

Concatenation

Concatenation is sometimes refered to as catenation. You can never lose any information when concatenating two sequences. An example of contatenation:
	S1		S2		S1^S2

	1 -> a		1 -> x		1 -> a
	2 -> b		2 -> y		2 -> b
	3 -> c				3 -> c
					(1+3 = 4) -> x	
					(2+3 = 5) -> y

Restriction

The signature for restriction is: (I'm using "|^" to represent the restriction symbol and "P" to be the power set symbol.)
	|^ : seq X x P X -> seq X
So, s |^ A means: take the sequence s, toss out any elements not in A, and squash the remaining parts of s back into a sequence (i.e. no gaps).

Head and Tail Defined

The notes give the signature for head as:
	head: seq1 X -> X
That is, a total function. This is because we restrict the source of the function to non-empty sequences (seq1). We could also have given the signature for head as:
	head: seq X -|-> X
That is, a partial function. Head is not defined for empty sequences, but we chose not to restrict the source of the function to non-empty sequences. Since there is an element in the source for which the function is undefined, it is partial.

If you define a function as partial, it's a nice idea to say what's excluded. In this case, dom head = seq X - {<>}.

Schemas

Arrows

Schema Notation

A schema is a convenient way of containing complicated declarations and predicates. It doesn't add anything new--it's just a different way of writing the things we've already been writing. The lines of a schema give an indication of scope.

The following two declarations are equivalent:

1)	x : N; y : Z


2)	--Name--------------------
	|  x : N
	|  y : Z
	--------------------------
	|  ...
	--------------------------

The following two predicates are equivalent:

1)	p1 ^ p2   (a conjunct)

2)	--Name--------------------
	|  ...
	--------------------------
	|  p1
	|  p2
	--------------------------

The operator "and" is implicit between the lines of a schema. The "or" operator must be written explicitly:

	--Name--------------------
	|  ...
	--------------------------
	|  p1 v
	|  p2
	--------------------------

The "equal sign with the hat over it" means that it is a schema definition, i.e. a thing that can be type-checked.

Our First Schema

[CH] is the set of all possible characters that can appear in the text editor. We don't say anything more specific than this because the basic behavior of a text editor is independent of the language (i.e. character set) it is operating on.

	--Editor-----------------------------------------------
	|  text : seq CH
	|  insertion : N
	--------------------------
	|  text != <> => insertion element_of dom text
	-------------------------------------------------------
(Note that the lecture notes contain a typo in the last line of this schema: {} should be <>. This typo occurs throughout the lecture notes.) The last line is a condition which must always be satisfied (an invariant). It says that if the text is not empty, the insertion point must be somewhere within the text. It does not tell us anything about the insertion point if the text is empty.

Schema Inclusion

The ability to include schemas in others allows a modular design -- which is the power of Z!

An example of inclusion:


   --R-------	--S-------	  	--S--------	
   | decl R	| R   	 	  	| decl R
   ----------   | decl S          	| decl S
   | pred R	----------   ==>        -----------
   ----------	| pred S	  	| pred S
		----------		| pred R
					-----------
		 	
Note that the precicates of S may refer to the declarations of R.

What about the case where R and S have variables with the same name?


   --R-------	--S-------	
   | a : N	| R
   | b : Z	| a : N   	 	
   ----------   ----------        
   | pred R	| pred S	
   ----------	----------   		 	
R can be included in S because the variable name they have in common ("a") has the same type. If the type does not match, inclusion is not allowed.

Q. How strict is type compatibility? In other words, are a : N and a : R type compatible since N is a subset of R?
A. Types must match exactly. A type that is a subset of another is not compatible with it.

Schema Conventions

Renaming

If we consider [CH] to be "the set of all possible tasks", then our Editor looks very much like a ToDo list. We simply rename the delarations in the Editor schema to develop the ToDo schema. Any properties that held for the Editor also hold for the ToDo list.

The ability to rename schemas is convenient for an important aspect of usability: consistancy. Consistant behavior between the two applications is guaranteed (to some extent) because they are using the same abstract specification.

State Change Example

(I'm using "A" to represent delta.)
	--Move Left----------------------------------
	| A Editor
	---------------------
	| insertion != 1   <- a precondition, the insertion point can't
	|		       already be a the left end
	|
	| text' = text	   <- must say what happens to each variable,
	|			even if nothing happens
	|
	| insertion' = insertion - 1
	----------------------------------------------
Precondidions can be easily identified because they don't involve any decorated variables.

If the schema does not say what happens to a variable, all we know about it is that the invarients in the original schema still hold--we may not know a specific value for the variable.

Input and Output

Q. Why are preconditions usually specified with dom instead of < length? In other words why say:
	pos? element_of dom text
instead of
	pos? < #text
A. We use the domain restriction because it excludes numbers less than or equal to 0. Comparing to the length in the example above allows 0 as a valid position, which it is not.

Created May 18, 1995 16:16:28 by abowd@cc