Features declared obsolete at release two
At release two of Miranda in 1989 it was decided to remove the following
features from the the language
algebraic types with laws (=>)
algebraic types with field annotations for strictness (!)
These features had been found to be of rather marginal value, and they
introduce significant and undesirable complications into the semantics.
For the time being they are still supported by the compiler, so no-one
loses a working script, but they are no longer officially part of
Miranda and their use now attracts an `obsolete feature' warning at each
compilation. At some stage in the future (probably at the next release)
they will cease to be supported by the compiler.
Laws
Here is a method for translating Miranda code using laws into equivalent
code not using this feature. We take an example from the Nancy
paper (Turner 1985), of self-ordering lists, for illustration
--------------------------------------------------------
| |
| olist ::= Onil | Ocons num olist |
| |
| Ocons a (Ocons b x) => Ocons b (Ocons a x), if a>b |
| |
--------------------------------------------------------
For each constructor which has laws associated with it (in this case
Ocons) we introduce a new function name (`ocons' say). Now we make two
changes to the script
1) Throughout the script (including the rhs of the laws) replace all
right-hand-side occurences of the lawful constructors by the associated
function names. Only the `left-hand-side' uses of the constructor, i.e.
in pattern matching, are left alone.
2) Turn each law into a function definition, by replacing the
outermost occurrence of the constructor on the lhs of the law by the
associated function name, and replacing each `=>' by `='. We must also
add a last case to the function definition, stating that it is equal to
a call of its associated constructor on the same arguments if no earlier
case applies.
The definition of olist now looks like this
--------------------------------------------------------
| |
| olist ::= Onil | Ocons num olist |
| |
| ocons a (Ocons b x) = ocons b (ocons a x), if a>b |
| ocons a x = Ocons a x |
| |
--------------------------------------------------------
and throughout the rest of the code any occurences of `Ocons' other than
in pattern matching is likewise replaced by the function `ocons'. This
translation must preserve the behaviour of the script (because it
corresponds exactly to the way in which laws are implemented).
[A comment on this translation:-
Notice that the fact that objects of type `olist' are ordered now
depends on a voluntary discipline by the programmer - that he always
builds his olists by calling the function ocons, and never by using the
raw constructor Ocons. So the original script using laws had a security
about it that the translation no longer expresses - if we come back
later and add new code, we might `forget' the discipline and
accidentally build a non-ordered olist, by calling Ocons directly.
The proper solution to this is to make olist into an abstract data type
(although this will involve a more radical rewrite of your script). In
fact the main reason for dropping lawful types from Miranda is the
observation that the abstype declaration is a cleaner and more general
mechanism for introducing unfree types.
For example here is a possible definition of ordered lists as an
abstract type
abstype olist
with onil :: olist
ocons::num->olist->olist
ohd::olist->num
otl::olist->olist
oempty::olist->bool
olist == [num] ||constraint: the list is kept ordered, see below
ocons a (ocons b x) = b:ocons a x, a>b
ocons a x = a:x, otherwise
ohd = hd
otl = tl
oempty = (=[])
In the rest of the script we can manipulate olists ONLY by calling the
functions declared in the signature of the abstype (that is, the
information following the `with'). It is therefore logically impossible
to create a non-ordered olist. One thing has been lost - in the rest of
the script we can no longer do pattern matching on olists - but that is
a small price to pay for security.
end of comment]
Strictness annotations
The semantic effect of a strictness annotation (!) after a field in an
algebraic type definition is to make certain expressions evaluate to
BOTTOM (error or non-termination) that would otherwise have had a value.
It therefore follows that removing all the strictness annotations must
be semantically harmless - it cannot introduce an error into a working
program.
A secondary purpose of strictness annotations was to gain some control
over space behaviour by forcing some constructors to be call-by-value in
some of their arguments. However, if you are interested in modifying
the space behaviour of your programs by changing the order of
evaluation, you can always use `force' and `seq' to do this explicitly.
For example, if you wish data structure x to be fully evaluated before
being passed to function f, you can write
seq (force x) (f x)
------------------------------------------------------------------------
Reference: 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 201:1-16).
this can be found at http://miranda.org.uk