summaryrefslogtreecommitdiff
path: root/miralib/manual/21
diff options
context:
space:
mode:
Diffstat (limited to 'miralib/manual/21')
-rw-r--r--miralib/manual/21133
1 files changed, 133 insertions, 0 deletions
diff --git a/miralib/manual/21 b/miralib/manual/21
new file mode 100644
index 0000000..57f1a4e
--- /dev/null
+++ b/miralib/manual/21
@@ -0,0 +1,133 @@
+_A_b_s_t_r_a_c_t_ _t_y_p_e_ _d_e_f_i_n_i_t_i_o_n_s
+
+These enable a new data type to be defined by data type abstraction from
+an existing type. We give the classic example, that of defining `stack'
+as an abstract data type (here based on lists)
+ _a_b_s_t_y_p_e stack *
+ _w_i_t_h empty::stack *
+ push::*->stack *->stack *
+ isempty::stack *->bool
+ top::stack *->*
+ pop::stack *->stack *
+
+ stack * == [*]
+ empty = []
+ push a x = a:x
+ isempty x = x=[]
+ top (a:x) = a
+ pop (a:x) = x
+
+The information given after `_w_i_t_h' is called the _s_i_g_n_a_t_u_r_e of the
+abstract type - the definitions of the identifiers in the signature are
+called the `implementation equations' (these are the six equations given
+above). Outside of the implementation equations the information that
+stacks are implemented as lists is not available - [] and empty for
+example are incomparable objects of two different and unrelated types (
+[*] and stack * respectively). Only inside the implementation equations
+are the abstract objects treated as being equivalent to their
+representations.
+
+The implementation equations do not have to appear immediately after the
+corresponding _a_b_s_t_y_p_e declaration - they can occur anywhere in the
+script. For readability, however, it is strongly recommended that the
+implementation equations appear immediately after the _a_b_s_t_y_p_e
+declaration.
+
+Note that in Miranda there is no runtime cost associated with
+administering an abstract data type. The responsibility for enforcing
+the distinction between stacks and lists, for example, is discharged
+entirely at compile time (by the type checker). The runtime
+representation of a stack does not require any extra bits to distinguish
+it from a list. As a result the Miranda programmer can freely use
+abstract data types to structure his programs without incurring any loss
+of efficiency by doing so.
+
+Notice that the mechanism used to introduce abstract data types in
+Miranda does not depend on the hiding of identifiers, and in this
+respect differs from the traditional approach. A fuller discussion of
+the Miranda _a_b_s_t_y_p_e mechanism can be found in [*Turner 85].
+
+------------------------------------------------------------------------
+(*) D. A. Turner ``Miranda: A Non-Strict Functional Language with
+Polymorphic Types'', Proceedings IFIP Conference on Functional
+Programming Languages and Computer Architecture, Nancy, France,
+September 1985 (Springer Lecture Notes in Computer Science, vol. 201, pp
+1-16).
+------------------------------------------------------------------------
+
+_T_h_e_ _p_r_i_n_t_ _r_e_p_r_e_s_e_n_t_a_t_i_o_n_ _o_f_ _a_b_s_t_r_a_c_t_ _o_b_j_e_c_t_s
+ ("advanced feature" - omit on first reading)
+
+Values belonging to an abstract type are not in general printable. If
+the value of a command-level expression is of such a type it will
+normally print simply as
+
+<abstract ob>
+
+This is because the special function _s_h_o_w (which is actually a family of
+functions, see elsewhere) has no general method for converting such
+objects to a printable form. It is possible to extend the definition of
+_s_h_o_w to include the ability to print members of an abstract type, using
+some appropriate format. The convention for doing this is to include in
+the definition of the abstract type a function with the name `showfoo'
+(where `foo' is the name of the abstract type involved).
+
+We illustrate how this is done taking `stack' as the example. Suppose
+we decide we wish stacks to print - using a syntax such that the output
+could be read back in (e.g. by readvals - see elsewhere) to generate the
+same stack.
+
+ empty is to print as "empty"
+ push 1 empty is to print as "(push 1 empty)"
+ and so on.
+
+Note that we decide to fully parenthesise the output for safety - since
+we do not know the larger context in which our stack output may be
+embedded.
+
+Because `stack' is a polymorphic abstraction, showstack will need to
+take as a parameter the appropriate show function for the element type
+(which is num in the above examples, but could have been any type). We
+add to the signature of stack the following function.
+
+ showstack::(*->[char])->stack *->[char]
+
+To obtain the output format illustrated above, an appropriate definition
+of showstack would be,
+
+ showstack f [] = "empty"
+ showstack f (a:x) = "(push " ++ f a ++ " " ++ showstack f x ++ ")"
+
+If this definition is included in the script, stacks become printable,
+using the specified format. The effect is to extend the behaviour of
+the special built-in function _s_h_o_w to handle stacks, and all data
+structures built using stacks (such as list of tree of stacks, stack of
+stacks and so on).
+
+The general rule is as follows. Let `foo' be an abstract type name. To
+make foo's printable, we need to define a `showfoo' thus:
+
+ if foo is a simple type (not polymorphic)
+ showfoo :: foo -> [char]
+
+ if foo is polymorphic in one type variable (foo *)
+ showfoo :: (*->[char]) -> foo * -> [char]
+
+ if foo is polymorphic in two type variables (foo * **)
+ showfoo :: (*->[char]) -> (**->[char]) -> foo * ** -> [char]
+
+and so on. Note that the show function must be declared in the
+signature of the abstract type, and that the name of the function is
+significant - if we change its name from `showfoo' to `gobbledegook',
+its definition will cease to have any effect on the behaviour of _s_h_o_w.
+It also needs to have the right type, and if it does not, again its
+presence will have no effect on the behaviour of _s_h_o_w (in this case the
+compiler prints a warning message).
+
+[Note on library directives: If you %export an abstract type, foo say,
+to another file, it is not necessary to %export the showfoo function
+explicitly to preserve the correct printing behaviour - if an abstract
+type comes into existence with a show function in its signature the
+compiler will `remember' how to print objects of the type even in scopes
+where the show function has no name.]
+