Bill Page wrote:
On November 22, 2005 3:38 PM Peter Broadbery wrote:
Bill Page wrote:
Yet the ability to use 'pretend' is critical to the concept
of representation in the construction of Axiom domains.
For a perhaps overly abstract discussion of this see:
http://wiki.axiom-developer.org/RepAndPer
Just one comment to this website. I don't think that
rep: % -> Rep
could be seen as a forgetful functor. Surely, it forgets the signatures
of % (ie, its category), but it also introduces a structure.
Take, for example,
IntegerGroup: Group == add {
Rep == Integer;
(x: %) + (y: %): % == per(rep x + rep y);
...
}
Here rep forgets the Group structure of % and gains (at least) the Ring
structure of Integer.
So my question is: Does this feature of the Spad and Aldor
languages actually make them "weakly typed"?
I'd say it does, at least for some definitions of the term.
I'd very quickly follow up by saying 'but who cares', since
it's obvious that they occasionally have their uses (as Tim
suggests, system level code, and where you just know that
your domain is implemented in a particular way). I've rarely
seen a need for the second use, but one persons app level
could be system level to someone else, I guess.
I would be interested to learn of any examples where this sort
of use of 'pretend' was essential, i.e. where it can not be
replaced with some operations defined on the underlying domains.
I think it was nowhere essential. If a programmer thinks for some
efficiency reasons to pretend that some A is some particular type B that
might come from the fact that A does not provide certain functions. I
would argue, that in this case A is simply not rich enough. So the
design was not the best from the beginning.
See also
http://www.aldor.org/docs/HTML/chap7.html#6
I cannot remember that I have seen pretend being used in some essential
way. Anyway, if it were essential, then I'd rather like to have all such
domains defined at a very low level and forbid "pretend" for all users
who are going to implement mathematics.
There is some use of "pretend" though, where I could not do without it.
bar(F: Field): F == ...
foo(R: Ring): () == {
...
if R has Field then result:= bar(R);
else result:= 1;
result;
}
The Aldor compiler should be able to compile such code, but the current
implementation does not realize in all cases that in bar(R) the R is
actually a field, so I'd have to say "bar(R pretend Field)". However,
that is a weakness of the compiler and not a necessity for "pretend".
(P.S.: I don't claim that this particular piece of code above does not
compile, but I remember that I experienced cases, where the structure
was similar.)
For Rep, rep and per, I (personally) believe they should have
been language primitives, except that add-inheritance confuses
the issue a little. They should definitely be thought of as
primitive.
I fully agree, although I don't quite understand that part "except that
add-inheritance confuses the issue a little". But I think the language
designers were minimalistic. Instead of introducing two primitives "rep"
and "per", they introduced only "pretend".
There is an idea of adding a third operation 'per?', defined
by the programmer which tests if an object of type Rep is
really a member of %, and would be called immediately before
each 'per' operation. I'd hate to be forced to write it each
time though.
How can they be different anyway? To me it is even not completely clear
whether Rep is a language primitive or not. I don't remember that I have
read anything about Rep being a primitive, furthermore, some time ago
one would have written "Rep ==> Integer" and not "Rep==Integer" as it is
suggested now. See
http://www.aldor.org/docs/HTML/chap7.html#8 (subsection Representation).
since the representation is supposed to be purely internal to
the domain, right?.
And this is an advantage. Let's look at the Aldor libraries. There are
two variants, libaldor.al and libaldord.al. The second one is a "DEBUG"
version and sometimes quite handy to find bugs. Take, for example, the
implementation of PritiveArray in both libraries.
It starts like this.
PrimitiveArray(T:Type): PrimitiveArrayType T == add {
import from Machine;
#if DEBUG
Rep == Record(sz:Z, data:Arr);
local size(x:%):Z == {import from Rep;
empty? x => 0; rep(x).sz
}
local arr(x:Arr, n:Z):% == {import from Rep;
zero? n => empty; per [n,x]
}
local data(x:%):Arr == {
import from Rep;
empty? x => (nil$Pointer) pretend Arr;
rep(x).data;
}
#else
Rep == Arr;
local data(x:%):Arr == rep x;
local arr(x:Arr, n:Z):% == per x;
local arr(x:Arr):% == per x;
#endif
array(p:Pointer, n:Z):% == arr(p pretend Arr, n);
pointer(a:%):Pointer == data(a) pretend Pointer;
So if you are going to use PrimitiveArray later in your program, you
could hardly use "pretend" until you happen to have the sources and know
the dependency on the DEBUG flag.
But for the outside world both are indistinguishable, because they are
both of PrimitiveArrayType(T).
Oh, I am just realizing here is also a "pretend Arr". That is low level
programming and completely hidden in PrimitiveArray. But this also looks
like efficiency considerations. If there were a better documentation of
Arr available then it would certainly be unecessary. But then maybe Arr
would use "pretend" or is completely implemented in C or so. One has to
start somewhere, so consider PrimitiveArray as a primitive type and
never worry about "pretend" anymore when building on it.
Ralf
_______________________________________________
Axiom-developer mailing list
Axiom-developer@nongnu.org
http://lists.nongnu.org/mailman/listinfo/axiom-developer