changeset 27:5de03f77dae1

Added documentation about types and revised arrow type specifications.
author samer
date Sat, 19 Jan 2013 14:22:09 +0000
parents 8f4a21082c45
children 673b8e45d05a
files README.txt arrows/@afirst/afirst.m arrows/@agraph/agraph.m arrows/@aparallel/aparallel.m arrows/@arr/arr.m arrows/@arrf/arrf.m arrows/@arrow/arrow.m arrows/@arrow/construct.m arrows/@arrow/first.m arrows/@arrow/mkunit.m arrows/@aswitch/aswitch.m arrows/@erate/erate.m arrows/@loop1/loop1.m arrows/anull.m arrows/arrow_repl.m arrows/perm.m arrows/umgather.m arrows/with_arrow.m general/funutils/@thunk/thunk.m
diffstat 19 files changed, 140 insertions(+), 25 deletions(-) [+]
line wrap: on
line diff
--- a/README.txt	Sat Jan 19 13:09:31 2013 +0000
+++ b/README.txt	Sat Jan 19 14:22:09 2013 +0000
@@ -39,4 +39,119 @@
 
   * Type specification language
 
+  Since learning about Haskell many years ago, it has become my favourite language that
+  I never program in. One result of this is that I have gradually evolved a semi-formal
+  type specification language for Matlab functions and values, which I use in the function
+  header comment. The format of a type declaration is as follows:
 
+      <name> :: <type_spec>.
+      <type_spec> ::= <type> [~ '<description>'] 
+
+  <name> is a valid Matlab identifier, starting with an alphebetic character and
+  continuing with alphabetic or numeric characters or underscores. 
+  <description> consists of any characters valid in Matlab single-quoted string, and
+  is intended as a place to insert arbitrary annotations in a structured way.
+  The various type constructors are defined as follows. Capital letters denote variables.
+
+  Primitive types
+
+     real          - double or single precision floating point value
+     complex       - double or single precision complex floating point value
+     nonneg        - real number >=0 
+	  int           - integer
+	  natural       - integers starting at 0 or 1 
+	  bool          - true or false (Matlab allows 0 or 1)
+	  string        - Matlab string (array of characters)
+	  A..B          - Integers between A and B inclusive
+	  A--B          - Real numbers between A and B inclusive
+	  [A]           - Integers between 1 and A inclusive
+     [A,B,..]      - Comma separated list of integers in 1..A, 1..B etc (used for array domains) 
+     A|B           - Non-discrimitated union, value of type A or B (not recommended to use if possible)
+     {A,B,C}       - Value from the enumerated set, eg {0,1,2} is equivalent to 0..2 (also deprecated)
+
+  Array types
+
+     [D->R]        - Array with domain (ie size)  D and element type R
+     [D]           - Array with domain D and real elements
+     {D->R}        - Cell array with domain D and elements of type R
+
+  Function types
+
+     <type_list> -> <type_list>   - A functional function (no side effects) with input and output types.
+     <type_list> => <type_list>   - An action with side effects, with input and output types.
+
+	  <type_list> ::= <type_spec> [, <type_list>]
+
+  Cells and tuples
+
+     cells(A)         - arbitrary length row array of cells (list) of type A, equivalent to {[1,N]->A}
+	  cell {A1,..,AN}  - 1xN cell array with exactly the give types, ie, a tuple
+     pair(A,B)        - equivalent to cell {A,B}.
+
+  Structures 
+
+     struct { <field_list> }  - Structure with specified fields.
+	  <field_list> ::= <name> :: <type_spec> [ ; <field_list> ] 
+
+  Options 
+
+     Options are an indefinite length list of trailing arguments specifying name-value pairs,
+	  used to pass values of optional named arguments. Functions are expected to use default
+	  values for named arguments not specified. Structures can be used to pass several names-value
+	  pairs at once.
+
+     options { <option_list> }  - Abitrary length list of arguments specifying optional values
+	  <option_list> ::= <option_spec> [ ; <option_list> ] 
+	  <option_spec> ::= <name> :: <type> [/<default_value>] [~'<description>']
+
+  Dependent types
+
+     Dependent types are use for functions where the type some argument or return depends on
+	  the *value* of one of the arguments. These are most useful when the size of a returned array
+	  depends on the value of a numerical input. Specifying these types requires some way to bind the
+	  value of an argument to a variable in the type specification, for which purpose a single colon ':'
+	  is used. We revise the type specification definition as follows:
+
+	     <type_spec> ::= [<variable> :] <type> [~'<description']
+
+	  For example, the matlab function eye has type:
+
+	     eye :: N:natural -> [[N,N]].
+
+     Which means that the first argument is a natural number with value N, the return value is
+	  a square N-by-N array or real numbers.
+
+
+  Variable length argument and return lists
+
+    This has been the least consistent part of the type language and has changed as the 
+    language relaxed from its rather Haskellish beginning, where variable length argument
+    and return lists really don't fit, into a more Matlaby state. In particular, I've ended
+    up using Matlab's own concept of a 'comma separated list', as distinct from any kind of
+    array, to represent a list of argument or return types.
+
+    A comma separated list is literally a sequence of things separated by commas, eg
+	    A, B, C, D
+    such as those that appear in various places in Matlab code, eg,
+	    [<list>] = f(1,<list>);
+		 x = [<list>];
+		 y= x(<list>);
+
+    If A is a cell-array containing N elements, ie A = { a1, a2, ..., aN }
+    then A{:} denotes a comma-separated list of its elements, ie
+	    A{:}   ==  A{1}, A{2}, ..., A{N}
+    So, if A and B are lists of types, eg A = { real, natural } and B = {[[2,2]], real }, then
+	    A{:} -> B{:}   <denotes>   real, natural -> [[2,2]], real
+    ie, a valid function type. Similarly, 
+	    cell A == cell {A{:}} == cell {real, natural} == pair(real,natural)
+
+    If a variable such as A is used in a type specification, and we wish to emphasise
+	 the fact that A denotes a cell array or list of N types, then we can write A@typelist(N).
+	 This is a bit clunky and is a hangover from a previous method of specifying argument
+	 lists - perhaps it shoud be A@X, where X is any type of types (ie a *kind*), eg
+
+	     cells(type) - arbirary list of types
+		  {[N]->type} - list of N types
+
+	
+
--- a/arrows/@afirst/afirst.m	Sat Jan 19 13:09:31 2013 +0000
+++ b/arrows/@afirst/afirst.m	Sat Jan 19 14:22:09 2013 +0000
@@ -1,7 +1,7 @@
 % afirst - arrow that applies some arrow to first input and passes rest through
 %
 % afirst :: 
-%    arrow(A:arglist(N),B:arglist(M),S),
+%    arrow(A@typelist(N),B@typelist(M),S),
 %    L:natural ~'the number of extra inputs to pass through'
 % -> arrow([A,{[L]->type}], [B,{[L]->type}],S).
 %
--- a/arrows/@agraph/agraph.m	Sat Jan 19 13:09:31 2013 +0000
+++ b/arrows/@agraph/agraph.m	Sat Jan 19 14:22:09 2013 +0000
@@ -6,7 +6,7 @@
 %       fig :: handle / gcf  ~'figure for this instance';
 %       autoflush :: boolean/1 ~'unit will call drawnow after every iteration'
 %    }
-% -> agraph(N) < arrow(_:arglist(N),{},_).
+% -> agraph(N) < arrow(_@typelist(N),{},_).
 %
 % METHODS
 %    autoflush :: agraph(_) -> boolean.
--- a/arrows/@aparallel/aparallel.m	Sat Jan 19 13:09:31 2013 +0000
+++ b/arrows/@aparallel/aparallel.m	Sat Jan 19 14:22:09 2013 +0000
@@ -1,8 +1,8 @@
 % aparallel - Parallel application of arrows to multiple inputs
 %
 % aparallel :: 
-%    arrow( A1:arglist(N1), B1:arglist(M1), C1) ~'arrow with N1 inputs, M1 outputs',
-%	  arrow( A2:arglist(N2), B2:arglist(M2), C2) ~'arrow with N2 inputs, M2 outputs',
+%    arrow( A1@typelist(N1), B1@typelist(M1), C1) ~'arrow with N1 inputs, M1 outputs',
+%	  arrow( A2@typelist(N2), B2@typelist(M2), C2) ~'arrow with N2 inputs, M2 outputs',
 % -> arrow( [A1,A2], [B1,B2],cell {C1,C2})      ~'arrow with N1+N2 ins, M1+M2 outs'.
 %
 % The list of inputs of the second arrow is concatenated to those
--- a/arrows/@arr/arr.m	Sat Jan 19 13:09:31 2013 +0000
+++ b/arrows/@arr/arr.m	Sat Jan 19 14:22:09 2013 +0000
@@ -1,12 +1,12 @@
 % arr - Lift function to processing unit
 %
 % arr :: 
-%    F:(A:arglist(N)->B:arglist(M)) ~'arbitrary function with N inputs and M outputs',
+%    F:(A@typelist(N)->B@typelist(M)) ~'arbitrary function with N inputs and M outputs',
 %    options { 
 %       nargin  :: natural / nargin(F);
 %       nargout :: natural / nargout(F);
 %    }
-% -> arrow(A:arglist(N),B:arglist(M),empty).
+% -> arrow(A@typelist(N),B@typelist(M),empty).
 %
 % The arr class is a class of arrows which simply apply an ordinary
 % Matlab function to the inputs to obtain the outputs. In many cases,
--- a/arrows/@arrf/arrf.m	Sat Jan 19 13:09:31 2013 +0000
+++ b/arrows/@arrf/arrf.m	Sat Jan 19 14:22:09 2013 +0000
@@ -1,11 +1,11 @@
 % arrf - Creat functional arrow using a function factory
 %
 % arrf :: 
-%    FF: (SZ -> (A:arglist(N)->B:arglist(M))) ~'function to create function from sizes',
+%    FF: (SZ -> (A@typelist(N)->B@typelist(M))) ~'function to create function from sizes',
 %    N: natural ~'number of inputs',
 %    M: natural ~'number of outputs',
 %    options {}
-% -> arrow(A:arglist(N),B:arglist(M),empty).
+% -> arrow(A@typelist(N),B@typelist(M),empty).
 %
 % The type empty denotes the type of empty arrays, ie
 % the state of an arr arrow is always an empty matrix.
--- a/arrows/@arrow/arrow.m	Sat Jan 19 13:09:31 2013 +0000
+++ b/arrows/@arrow/arrow.m	Sat Jan 19 14:22:09 2013 +0000
@@ -3,7 +3,7 @@
 % arrow :: 
 %    N:natural ~'number of inputs',
 %    M:natural ~'number of inputs'
-% -> arrow(T1:arglist(N),T2:arglist(M),_).
+% -> arrow(T1@typelist(N),T2@typelist(M),_).
 %
 % The arrow(T1,T2,S) type denotes the type of an arrow with N inputs
 % and M outputs when T1 is a list of N types and T2 is list of M types.
--- a/arrows/@arrow/construct.m	Sat Jan 19 13:09:31 2013 +0000
+++ b/arrows/@arrow/construct.m	Sat Jan 19 14:22:09 2013 +0000
@@ -1,7 +1,7 @@
 % construct - Instantiate live processing unit
 %
 % construct :: 
-%    arrow(A:arglist(N), B:arglist(M), S) ~'the arrow to instantiate',
+%    arrow(A@typelist(N), B@typelist(M), S) ~'the arrow to instantiate',
 %    {[N]->size}                          ~'the sizes of the inputs'
 % -> unit(A,B,S)                          ~'live processing unit structure'.
 %
@@ -10,7 +10,7 @@
 % values and functions for running the live processing unit. Its fields
 % are as follows:
 %
-% unit(A:arglist(N),B:arglist(M),S) :== struct {
+% unit(A@typelist(N),B@typelist(M),S) :== struct {
 %       starting :: () -> action ();
 %       stopping :: () -> action ();
 %       dispose  :: () -> action ();
--- a/arrows/@arrow/first.m	Sat Jan 19 13:09:31 2013 +0000
+++ b/arrows/@arrow/first.m	Sat Jan 19 14:22:09 2013 +0000
@@ -1,7 +1,7 @@
 % first - Apply arrow to first input and pass through others
 %
 % first :: 
-%    arrow(A:arglist(N),B:arglist(M)),
+%    arrow(A@typelist(N),B@typelist(M)),
 %    L:natural ~'the number of extra inputs to pass through'
 % -> arrow([A,{[L]->type}], [B,{[L]->type}]).
 %
--- a/arrows/@arrow/mkunit.m	Sat Jan 19 13:09:31 2013 +0000
+++ b/arrows/@arrow/mkunit.m	Sat Jan 19 14:22:09 2013 +0000
@@ -5,7 +5,7 @@
 % structure representing a live processing unit.
 %
 % mkunit :: 
-%    arrow(_:arglist(N),_:arglist(M),S) 
+%    arrow(_@typelist(N),_@typelist(M),S) 
 % -> struct {
 %       starting :: () -> action ();
 %       stopping :: () -> action ();
--- a/arrows/@aswitch/aswitch.m	Sat Jan 19 13:09:31 2013 +0000
+++ b/arrows/@aswitch/aswitch.m	Sat Jan 19 14:22:09 2013 +0000
@@ -1,7 +1,7 @@
 % aswitch - switching arrow 
 %
 % aswitch :: 
-%    arrow(A:arglist(N),B:arglist(M),S)
+%    arrow(A@typelist(N),B@typelist(M),S)
 % -> arrow([A,{box(arrow(A,B,S))}], B,S).
 %
 % The resulting arrow has N+1 inputs and M outputs. The last input
--- a/arrows/@erate/erate.m	Sat Jan 19 13:09:31 2013 +0000
+++ b/arrows/@erate/erate.m	Sat Jan 19 14:22:09 2013 +0000
@@ -1,6 +1,6 @@
 % erate - Drive sub-arrow at event rate, ie when events arrive
 %
-% erate :: arrow(A:arglist(N),B:arglist(M),S),
+% erate :: arrow(A@typelist(N),B@typelist(M),S),
 % -> arrow(events(A), events(B),S).
 %
 % the type events(A) denotes a list of types where each
--- a/arrows/@loop1/loop1.m	Sat Jan 19 13:09:31 2013 +0000
+++ b/arrows/@loop1/loop1.m	Sat Jan 19 14:22:09 2013 +0000
@@ -3,7 +3,7 @@
 % loop1 ::
 %    N:natural  ~'number of inputs for this arrow',
 %    M:natural  ~'number of outputs for this arrow',
-%    ({[N]->size} -> ([A:arglist(N), {S}] -> [B:arglist(M), {S}])) 
+%    ({[N]->size} -> ([A@typelist(N), {S}] -> [B@typelist(M), {S}])) 
 %                           ~'function to map input sizes to state transformer',
 %    ({[N]->size} -> S0:S)  ~'function to map size of input to initial state'
 % -> arrow(A,B,S) ~'arrow from A to B with state of type S'.
--- a/arrows/anull.m	Sat Jan 19 13:09:31 2013 +0000
+++ b/arrows/anull.m	Sat Jan 19 14:22:09 2013 +0000
@@ -1,6 +1,6 @@
 % asink - Do nothing absorbing arrow
 %
-% asink :: N:natural -> arrow(_:arglist(N),{},empty).
+% asink :: N:natural -> arrow(_@typelist(N),{},empty).
 function a=asink(nin)
 	if nargin<1, nin=1; end
 	a=arr(@nop,'nargin',nin,'nargout',0);
--- a/arrows/arrow_repl.m	Sat Jan 19 13:09:31 2013 +0000
+++ b/arrows/arrow_repl.m	Sat Jan 19 14:22:09 2013 +0000
@@ -1,7 +1,7 @@
 % arrow_repl - Instantiate arrow system and drop into REPL.
 %
 % arrow_repl ::
-%    arrow(_:arglist(N),_:arglist(M),S)  ~'arbitrary arrow',
+%    arrow(_@typelist(N),_@typelist(M),S)  ~'arbitrary arrow',
 %    {[N]->size}                         ~'sizes of inputs'
 %    options {
 %       gui      :: boolean/false ~'create Java GUI for viewables'
--- a/arrows/perm.m	Sat Jan 19 13:09:31 2013 +0000
+++ b/arrows/perm.m	Sat Jan 19 14:22:09 2013 +0000
@@ -3,7 +3,7 @@
 % perm :: 
 %    N:natural ~'number of inputs',
 %    P:[[M]->[N]] ~'permutation of inputs'
-% -> arrow(_:arglist(N), _:arglist(M), empty).
+% -> arrow(_@typelist(N), _@typelist(M), empty).
 %
 % This function creates an arrow whos outputs can
 % be copies of any of the inputs in any order. 
--- a/arrows/umgather.m	Sat Jan 19 13:09:31 2013 +0000
+++ b/arrows/umgather.m	Sat Jan 19 14:22:09 2013 +0000
@@ -1,14 +1,14 @@
 % umgather - Run a processing unit and collect multiple outputs
 %
 % ugather :: 
-%    unit({}, A:arglist(K), _) ~'live processing unit with K outputs',
+%    unit({}, A@typelist(K), _) ~'live processing unit with K outputs',
 %    T:natural              ~'number of iterations to run (can be inf)',
 %    options {
 %       draw  :: boolean/false ~'whether or not to call drawnow after each iteration';
 %       quiet :: boolean/false ~'whether or not to suppress progress messages';
 %       chunk :: natural/1     ~'print progress every chunk interations';
 %    } 
-% -> B:arglist(K) ~'collected outputs'.
+% -> B@typelist(K) ~'collected outputs'.
 %
 % This function accepts the live processing unit associated
 % with an arrow (as created by with_arrow). The arrow must
--- a/arrows/with_arrow.m	Sat Jan 19 13:09:31 2013 +0000
+++ b/arrows/with_arrow.m	Sat Jan 19 14:22:09 2013 +0000
@@ -1,7 +1,7 @@
 % with_arrow - Instatiate processing network and run a command against it
 %
 % with_arrow ::
-%    arrow(T1:arglist(N),T2:arglist(M),S),
+%    arrow(T1@typelist(N),T2@typelist(M),S),
 %    Cmd:(unit(T1,T2,S) -> action R)  ~'function to apply to live unit',
 %    {[N]->size}                      ~'sizes of inputs',
 %    options {
--- a/general/funutils/@thunk/thunk.m	Sat Jan 19 13:09:31 2013 +0000
+++ b/general/funutils/@thunk/thunk.m	Sat Jan 19 14:22:09 2013 +0000
@@ -1,8 +1,8 @@
-% thunk(B:arglist(M)) ~ a thunk is something that eventually yields M outputs
+% thunk(B@typelist(M)) ~ a thunk is something that eventually yields M outputs
 classdef thunk
 	properties (GetAccess=private, SetAccess=immutable)
-		head %  ::  (A:arglist(N) -> B | thunk(B))
-		args %  ::  A:arglist(N)
+		head %  ::  (A@typelist(N) -> B | thunk(B))
+		args %  ::  A@typelist(N)
 	end
 	methods
 		% thunk - create delayed evaluation