summaryrefslogtreecommitdiff
path: root/miralib/manual/20
diff options
context:
space:
mode:
Diffstat (limited to 'miralib/manual/20')
-rw-r--r--miralib/manual/20126
1 files changed, 126 insertions, 0 deletions
diff --git a/miralib/manual/20 b/miralib/manual/20
new file mode 100644
index 0000000..2ca09d5
--- /dev/null
+++ b/miralib/manual/20
@@ -0,0 +1,126 @@
+_A_l_g_e_b_r_a_i_c_ _t_y_p_e_ _d_e_f_i_n_i_t_i_o_n_s
+
+The simplest method of introducing a new data type into a Miranda script
+is by means of an algebraic type definition. This enables the user to
+introduce a new concrete data type with specified constructors. A
+simple example would be
+ tree ::= Nilt | Node num tree tree
+
+The `::=' sign is used to introduce an algebraic data type. This
+definition introduces three new identifiers
+ `tree' a typename
+ `Nilt' a nullary constructor (i.e. an atom), of type tree
+ `Node' a constructor, of type num->tree->tree->tree
+
+Now we can define trees using constructors Nilt & Node, for example
+ t = Node 3 Nilt Nilt
+
+It is not necessary to have names for selector functions because the
+constructors can be used in pattern matching. For example a function
+for counting the number of nodes in a tree could be written
+ size Nilt = 0
+ size (Node a x y) = 1 + size x + size y
+
+Note that the names of constructors _m_u_s_t_ _b_e_g_i_n_ _w_i_t_h_ _a_n_ _u_p_p_e_r_ _c_a_s_e_ _l_e_t_t_e_r
+(and conversely, any identifier beginning with an upper case letter is
+assumed to be a constructor).
+
+An algebraic type can have any number (>=1) of constructors and each
+constructor can have any number (>=0) fields, of specified types. The
+number of fields taken by a constructor is called its `arity'. A
+constructor of arity zero is said to be atomic. Algebraic types are a
+very general idea and include a number of special cases that in other
+languages require separate constructions.
+
+One interesting case that all of the constructors can be atomic, giving
+us what is called in PASCAL a `scalar enumeration type'. Example
+ day ::= Mon|Tue|Wed|Thu|Fri|Sat|Sun
+
+The union of two types can also be represented as an algebraic data type
+- for example here is a union of num and bool.
+ boolnum ::= Left bool | Right num
+
+Notice that this is a `labelled union type' (the other kind of union
+type, in which the parts of the union are not distinguished by tagging
+information, is not permitted in Miranda).
+
+An algebraic typename can take parameters, thus introducing a family of
+types. This is done be using generic type variables as formal
+parameters of the `::=' definition. To modify our definition of `tree'
+to allow trees with different types of labels at the nodes (instead of
+all `num' as above) we would write
+ tree * ::= Nilt | Node * (tree *) (tree *)
+
+Now we have many different tree types - `tree num', `tree bool',
+`tree([char]->[char])', and so on. The constructors `Node' and `Nilt'
+are both polymorphic, with types `tree *' and `*->tree *->tree *->tree
+*' respectively.
+
+Notice that in Miranda objects of a recursive user defined type are not
+restricted to being finite. For example we can define the following
+infinite tree of type `tree num'
+ bigtree = Node 1 bigtree bigtree
+
+_C_o_n_t_r_o_l_l_i_n_g_ _t_h_e_ _s_t_r_i_c_t_n_e_s_s_ _o_f_ _c_o_n_s_t_r_u_c_t_o_r_s
+
+Definition - a function f is strict iff
+ f _| = _|
+where _| is the value attributed to expressions which fail to terminate
+or terminate with an error. To support non-strict functions the calling
+mechanism must not evaluate the arguments before passing them to the
+function - this is what is meant by "lazy evaluation".
+
+In Miranda constructors are, by default, non-strict in all their fields.
+Example
+
+ pair ::= PAIR num num
+ fst (PAIR a b) = a
+ snd (PAIR a b) = b
+
+First note that there is a predefined identifier "undef" which denotes
+undefined - evaluating "undef" in a Miranda session gives an error
+message. Consider the following Miranda expressions:
+
+ fst (PAIR 1 undef)
+ snd (PAIR undef 1)
+
+Both evaluate to `1', that is `PAIR' is non-strict in both arguments.
+
+The primary reason for making constructors non-strict in Miranda is that
+it is necessary to support equational reasoning on Miranda scripts. (In
+the example given, elementary equational reasoning from the definition
+of `fst' implies that `fst(PAIR 1 anything)' should always have the
+value `1'.) It is also as a consequence of constructors being non-strict
+that Miranda scripts are able to define infinite data structures.
+
+It is, however, possible to specify that a given constructor of an
+algebraic data type is strict in one or more fields by putting `!' after
+the field in the `::=' definition of the type. For example we can
+change the above script to make PAIR strict in both fields, thus
+
+ pair ::= PAIR num! num!
+ fst (PAIR a b) = a
+ snd (PAIR a b) = b
+
+Now `fst (PAIR 1 undef)' and `snd (PAIR undef 1)' both evaluate to
+undefined. It is a consequence of the `!' annotations that `PAIR a b'
+is undefined when either a or b is undefined. It is also possible to
+make PAIR strict in just one of its fields by having only one `!' in the
+type definition.
+
+In the case of a recursively defined algebraic type, if all the
+constructors having recursive fields are made strict in those fields it
+ceases to be possible to construct infinite objects of that type. It is
+also possible to deny the possibility of certain infinite structures
+while permitting others. For example if we modify the definition of the
+tree type first given above as follows
+ tree ::= Nilt | Node num tree! tree
+
+then it is still possible to construct trees which are infinite in their
+right branch but not "left-infinite" ones.
+
+The main reason for allowing `!' annotations on Miranda data type
+definitions is that one of the intended uses of Miranda is as a SEMANTIC
+METALANGUAGE, in which to express the denotational semantics of other
+programming languages.
+