What is difference from an array? Efficiency, esp. w/update.
update f arg result x = if x = arg then result else f xor
update f arg result = fn x => if x = arg then result else f xProcedure can be treated as having type S -> unit for uniformity.
set of elt_type;Typically implemented as bitset or linked list of elts
Operations and relations: All typical set ops, :=, =, subset, .. in ..
Why need base set to be primitive type? What if base set records?
tree = Empty | Mktree of int * tree * treeIn most lang's built by programmer from pointer types.list = Nil | Cons of int * list
Sometimes supported by language (e.g. Miranda, Haskell, ML).
Why can't we have direct recursive types in ordinary imperative languages?
OK if use ref's:
list = POINTER TO RECORD first:integer; rest: list END;
Recursive types may have many sol'ns
E.g. list = {Nil} union (int x list) has following sol'ns:
Theoretical result: Recursive equations always have a least solution - though infinite set if real recursion.
Can get via finite approximation. I.e.,
list0 = {Nil}Very much like unwinding definition of recursive functionlist1 = {Nil} union (int x list0) = {Nil} union {(n, Nil) | n in int}
list2 = {Nil} union (int x list1) = {Nil} union {(n, Nil) | n in int} union {(m,(n, Nil)) | m, n in int}
...
list = Unionn listn
fact = fun n => if n = 0 then 1 else n * fact (n-1) fact0 = fun n => if n = 0 then 1 else undef fact1 = fun n => if n = 0 then 1 else n * fact0(n-1) = fun n => if n = 0, 1 then 1 else undef fact2 = fun n => if n = 0 then 1 else n * fact1(n-1) = fun n => if n = 0, 1 then 1 else if n = 2 then 2 else undef ... fact = Unionn factnNotice solution to T = A + (T->T) is inconsistent with classical mathematics!
datatype univ = Base of int | Func of (univ -> univ);
operations: hd, tail, cons, length, etc.
Persistent data - files.
Are strings primitive or composite?
var x : integer {bound at translation time}The variable can only hold values of that type. (Pascal/Modula-2/C, etc.)
FORTRAN has implicit declaration using naming conventions
In either case, run real danger of problems due to typos.
Example in ML, if
datatype Stack ::= Nil | Push of int;then define
fun f Push 7 = ...What error occurs?
Answer: Push is taken as a parameter name, not a constructor.
Therefore f is given type: A -> int -> B rather than the
expected: Stack -> B
Dynamic: Variables typically do not have a declared type. Type of value may vary during run-time. Esp. useful w/ heterogeneous lists, etc. (LISP/SCHEME).
Dynamic more flexible, but more overhead since must check type before performing operations (therefore must store tag w/ value).
Dynamic binding found in APL and LISP.
no characters or strings, no user-defined of any sort.
Arrays - at most 3-dim'l of built-in type. Subscripts begin at 1
Orig., restricted form of subscript expressions.
No records or sets. Many holes in typing.
Arrays of built-in types - no limit on dim'n, bounds any integers, semi-dynamic arrays
No records or sets. Strongly and statically typed.
Subranges Guard against errors, save space. (only for discrete types)
Array [1..10, 'a'..'z'] of Real = Array [1..10] of Array ['a'..'z'] of RealUser fooled into thinking Array[A,B] of C is AxB->C, but really A->B->C.
Any discrete type as index.
No semi-dynamic arrays. Result of 2 principles:
Type of actual parameters must agree w/ type of formals
Therefore, no general sort routines, etc.
The major problem with Pascal
Procedure x(...; procedure y;...)Fixed in (new) ANSI standard.
:
y(a,2);
No checking if type of file read in matches what was originally written.
2. Problems w/ type compatibility
Assignment compatibility:
When is x := y legal? x : integer, y : 1..10? reverse?
What if type hex = 0..15; ounces = 0..15;
var x : hex; y : ounces;
Is x := y legal?
Original report said both sides must have identical types.
When are types identical?
Ex.:
Type T = Array [1..10] of Integer; Var A, B : Array [1..10] of Integer; C : Array [1..10] of Integer; D : T; E : T;Which variables have the same type?
--> A, B and D, E only.
Structural not always easy. Let
T1 = record a : integer; b : real end; T2 = record c : integer; d : real end; T3 = record b : real; a : integer end;Which are the same?
Worse:
T = record info : integer; next : ^T end; U = record info : integer; next : ^V end; V = record info : integer; next : ^U end;
Ada uses Name EquivalenceA
Pascal & Modula-2 use Name Equivalence for most part. Check!
Modula-3 uses Structural Equivalence
Two types are assignment compatible iff
e.g., type Boolean is (False, True)
Can overload values:
Color is (Red, Blue, Green) Mood is (Happy, Blue, Mellow)If ambiguous can qualify w/ type names:
Color(Blue), Mood(Blue)Subranges Declared w/range attribute.
i.e., Hex is range 0..15
Other attributes available to modify type definitions:
Accurate is digits 20 Money is delta 0.01 range 0.00 .. 1000.00 -- fixed pt!Can extract type attributes:
Hex'FIRST -> 1 Hex'LAST -> 15Can initialize variables in declaration:
declare k : integer := 0
type Two_D is array (1..10, 'a'..'z') of Realor "Unconstrained" (what we called semi-dynamic earlier)
type Real_Vec is array (INTEGER range <>) of REAL;Generalization of open array parameters of MODULA-2.
Of course, to use, must specify bounds,
declare x : Real_Vec (1..10)or, inside procedure:
Procedure sort (Y: in out Real_Vec; N: integer) is -- Y is open array parameter Temp1 : Real_Vec(1..N); -- depends on N Temp2 : Real_Vec (Y'FIRST..Y'LAST); -- depends on parameter Y begin for I in Y'FIRST ..Y'LAST loop ... end loop; ... end sort;Note Ada also has local blocks (like ALGOL 60)
All unconstrained types (w/ parameters) elaborated at block entry (semi-dynamic)
String type is predefined open array of chars:
array (POSITIVE range <>) of character;
Can take slice of 1-dim'l array.
E.g., if
Line : string(1..80)Then can write
Line(10..20) := ('a','b',.'c','d','e','f','g','h','i','j') -- gives assignment to sliceBecause of this structure assignment, can have constant arrays.