_T_h_e_ _%_f_r_e_e_ _d_i_r_e_c_t_i_v_e_ _a_n_d_ _p_a_r_a_m_e_t_r_i_s_e_d_ _s_c_r_i_p_t_s It is permitted to construct a script containing definitions which are dependent on information which will be supplied only when the script is made the subject of a %_i_n_c_l_u_d_e directive. Such a script is said to be _p_a_r_a_m_e_t_r_i_s_e_d. This is indicated by the presence in the script of a directive of the form %_f_r_e_e { signature } where `signature' is a list of specifications of the identifiers for which bindings will be provided at %_i_n_c_l_u_d_e time. A script may contain at most one %_f_r_e_e directive, which must therefore give all the identifiers on which the script is parametrised. The %_f_r_e_e directive may appear anywhere in the script, but for clarity it is recommended that you place it at or near the top. For example a script (called "matrices" say) defining the notion of matrix sum and matrix product, for matrices of as-yet-unspecified element type, could be written as follows:- %_e_x_p_o_r_t matmult matadd %_f_r_e_e { elem :: _t_y_p_e zero :: elem mult, add :: elem->elem->elem } matrix == [[elem]] matadd :: matrix->matrix->matrix matadd xx yy = [[add a b|(a,b)<-zip2 x y]|(x,y)<-zip2 xx yy] matmult :: matrix->matrix->matrix matmult xx yy = outerprod innerprod xx (transpose yy) innerprod x y = sum [mult a b|(a,b)<-zip2 x y] _w_h_e_r_e sum = foldr add zero outerprod f xx yy = [[f x y|y<-yy]|x<-xx] Note that the identifiers declared under %_f_r_e_e may denote types as well as values. When we write a %_i_n_c_l_u_d_e directive for the above script we must provide bindings for all of its free identifiers. The bindings are given in braces following the pathname (and before the aliases, if any). Thus:- %_i_n_c_l_u_d_e "matrices" {elem==num; zero=0; mult=*; add=+; } In the scope of the script containing the above directive the identifiers `matmult' and `addmult' will be available at type [[num]]->[[num]]->[[num]] and will behave as if their definitions had been written using 0, (+), (*) in place of the identifiers zero, add, mult. The order in which the bindings are given is immaterial (it need not be the order in which the identifiers occurred in the %_f_r_e_e directive) but a binding must be given for each free identifier of the %included script. Note that the binding for a type is given using `==' and for a value using `='. If the types of all the bindings (taken together) are not consistent with the information given in the free directive of the %included script, or if any required binding is missing, the compiler will reject the %_i_n_c_l_u_d_e directive as incorrect. The main advantage of a parametrised script is that different bindings may be given for its free identifiers on different occasions. For example the same script "matrices" may be invoked with different bindings to provide a definition of matrix addition and multiplication over matrices with elements of type bool. Thus:- %_i_n_c_l_u_d_e "matrices" {elem==bool; zero=False; mult=&; add=\/; } It is even possible to %_i_n_c_l_u_d_e the same parametrised script twice in the same scope (presumably with different bindings for the free identifiers) but in this case it will be be necessary to alias apart the two sets of exported identifiers to avoid a nameclash. So we might add `b_matadd/matadd b_matmult/matmult' to the above directive if it were being used in the same script as the previous one. _M_i_s_c_e_l_l_a_n_e_o_u_s_ _p_o_i_n_t_s By default the identifiers declared %_f_r_e_e in a parametrised script are not exported from the script. As always this can be overridden by explicitly listing them in an %_e_x_p_o_r_t directive. Free typenames of non-zero arity are declared in the following style. %_f_r_e_e { stack * :: _t_y_p_e table * ** :: _t_y_p_e ... } The corresponding bindings could be as follows %_i_n_c_l_u_d_e ... {stack * == [*]; table * ** == [(*,**)]; ... } When a parametrised script exports a locally created typename (other than a synonym type), each instantiation of the script by a %_i_n_c_l_u_d_e is deemed to create a NEW type (this is relevant to deciding whether or not two types are the same for the purpose of readopting a type orphan, see previous manual section). This is because the compiler assumes that an abstract or algebraic type defined in a parametrised script will in general have an internal structure that depends on the free identifiers. Finally note that the bindings for the free identifiers of a parametrised script must always be given EXPLICITLY. For example suppose we wish to %_i_n_c_l_u_d_e the file "matrices" in a script already containing a type called `elem' over which we intend to do matrix multiplication. We must write %_i_n_c_l_u_d_e "matrices" {elem==elem; etc. } The binding `elem==elem' is not redundant, nor is it cyclic, because the two `elem's involved refer to two different scopes (on the left of the binding, that of the includee, and on the right that of the script containing the directive).