That is example of frequent and quite fundamental confusion.
Evaluating at point (called "specialization" in algebraic
context) is only partial homomorfizm. It works as expected
in "generic" cased but in general may fail (signal errors or
produce unexpected result). This is fundamental limitation,
we try to make it work but only as good faith effort (because
we can not promise that this will "always" work).
Actually wording above is problematic. For example in many
places we have Eltable(%, %) which if interpreted literaly
as "element of u indexed by i" leads to trouble with axiom
of foundation.
Actually, with literal interpretation as indices we should
not have 'Eltable(UniversalSegment(Integer), %)' because
segments are not elements of index set (that is segments
are not integers).
There is looser interpretation above given by the phrase
"can be viewed as a function". So probably we should
have "Error: if u is not applicable to i". However
what is applicable, that is domain of impled mapping
depends on specifics.
Also, original Axiom sources had separate 'elt : (%, U) -> %'
in linear aggregate with docstring having no mention of
error (but default implementation signalled error ...).
> Let me appreviate U==>UniversalSegment(Integer).
> What we should implement is a function (%, U)->%
>
> Let's look at ListAggregate of OneDimensionalArrayAggregate. Their elements
> are functions from a finite index set I into a set S.
> Clearly, the error condition (*) tells me that an implementation
> would have to give an error whenever u contains an integer that is
> not in I.
Literaly it should signal error because segment is not an integer,
so can not be an index...
> That clearly agrees with what you say about "error early in eager
> structures".
>
> Now Stream.
>
> ++ A stream is an implementation of a possibly infinite sequence using
> ++ a list of terms that have been computed and a function closure
> ++ to compute additional terms when needed.
>
> That tells me that a stream is either a (lazy) list (= finite stream), i.e.
> a function from a finite set I to S, or an infinite structure, i.e. a
> function from N (natural numbers starting from 1) to S.
Well, more fundamental is description from LazyStreamAggregate:
++ LazyStreamAggregate is the category of streams with lazy
++ evaluation. It is understood that the function 'empty?' will
++ cause lazy evaluation if necessary to determine if there are
++ entries. Functions which call 'empty?', e.g. 'first' and 'rest',
++ will also cause lazy evaluation if necessary.
We could add sometinig like
++ Elements of LazyStreamAggregate are computed only when strictly
++ needed. Lazy computation means that potential errors are
++ delayed, so errors are detected later than in case of normal
++ (eager) evaluation used by other aggregates. In some cases
++ computation that would signal error when using eager evaluation
++ can succeed when using lazy evaluation.
> For finite streams, I would say that it should behave exactly as in the list
> case. The only exception would be that the error occurs according to the
> laziness, i.e. early in the list case and when a non-existing index is
> accessed in the stream case.
It seems that we agree.
> For ininite streams there will be only an error if the lower index is
> less then minIndex(x).
>
> If x is a finite structure (eager of lazy) then I would interpret the
> specification of elt in such a way that x(a.. by c) must always give
> an error (in eager or lazy way).
Well, lazy way means that we get error only on actual access to
out of bound element. So code that test for presence of elements
can avoid error by not accessing unavailable elements.
> Actually, that is not what I would want or what would be similar to pythons
> slice semantics for lists of the semantics of Mathematica's span semantics.
>
https://reference.wolfram.com/language/ref/Span.html
> No it is not necessary that we must have the same semantics, but as a
> convenience for the user I think that
>
> [1,2,3,4](3..) (or [1,2,3,4](3.. by -1))
>
> should give [3,4] (or [3,2,1]) instead of an error even though
> the actual set of indices represented by the segment clearly contains an
> index that falls out of the allowed range of the list.
>
> So what do we want in this last case and how do we specify it in the
> ++-docstring of "elt"?
Well, that touch much bigger subject. I mentioned some time ago
conceptual integrity. We want behaviours of various functions to
fit common pattern. Original Axiom did that quite well. Of
course, we want to go forward, but we also need to look how
our design decisions affect the whole. AFAICS one part of
orignal design was desire to catch errors early. This includes
cases which are meaningful but do not fit well to formal rules
(especialy type rules). As an example 'sqrt' of negative
float signals errors, while some other systems return
complex value. Or (ufortunate) case with 'recip' where
'recip' in the ring fails, while 'recip' in the fraction
field would work. So there is cost to this approach.
But there are also benefits. Bugs are easier to fix
when errors are detected early. And following type
rules means that code is _much_ more understandable.
However, treating FriCAS code just as formal system
IMO would be too rigid. In some cases instead for
of mathematical argument we need more "lawyer like"
argument. Even if formal argument says a there
may be overriding principle that says differently.
I think this is the case with lazy evaluation, it
overrides our desire to detect errors early.
Concering documentation, there is somewhat debatable
what we should write. IMO trying to do formal
description is (at least now) futile: it is easy
to get formal description wrong, correct formal
descriptions tend to be rather long, so it would
be large task. And it is hard to correctly read
formal description, so its usfulness for most
users is limited. Hence, I think that currently
it is better to stay at informal level. Here
tricky question is how much background knowledge
is required and what should be left unstated.
There are some math books which try to be as explict
as possible. This may be good for beginners,
but in effect such books are long and frequently
miss advanced issues. There are other which
assume a lot of background. In case of FriCAS
I think that we should take math and programming
concepts as granted (necessary background) in
reference part. It makes sense to provide tutorials
to various concepts, but with understanding that
they are not exhaustive (both in depth and in
coverage of concepts).
--
Waldek Hebisch