Development of packages with Aldor

143 views
Skip to first unread message

Tobias Neumann

unread,
Feb 4, 2021, 1:08:53 PM2/4/21
to FriCAS - computer algebra system
Dear FriCAS group,

thinking about writing in Aldor instead of SPAD (to have better error messages and maybe less quirks) I came across a few issues. As an example I want to (again) write a wrapper over Taylor series with a subsequent 'approximate'  (see code below).

There seems to be an issue finding 'approximate' from UnivariateTaylorSeries (available through UnivariatePowerSeriesCategory):
[L32 C62] #1 (Error) There are no suitable meanings for the operator `approximate$UnivariateTaylorSeries(Expression(Integer), sym, x...'.

I was thinking that this might likely be the same issue as with SPAD, that is I have to check whether Expression(Integer) has the approriate 'coerce' and '^' operations. Unfortunately this does not seem solve the problem, and with the additional conditions as below 'taytest' is also no longer exposed.

I'd be happy about any suggestions.

---- SNIP ----
#include "fricas"

EI ==> Expression(Integer);

-- in SPAD
--        if ECFI has coerce : Symbol -> ECFI and
--           ECFI has _^ : (ECFI, Fraction (Integer)) -> ECFI then

TaylorPackage: with {
   if EI has with { coerce: Symbol -> EI } and EI has with { ^: (EI, NonNegativeInteger) -> EI } then {
       taytest: (EI,EI,Symbol) -> EI;
   };
   testfun : Integer -> Integer;

} == add {

testfun(x: Integer) : Integer == {
    x
};

taytest(ex: EI, x0: EI, sym: Symbol) : Expression(Integer) == {
    import from Integer;
    import from NonNegativeInteger;
    import from ExpressionToUnivariatePowerSeries(Integer,Expression(Integer));
    import from Equation(EI);
    import from UnivariateTaylorSeries(EI,sym,x0);

    local test : UnivariateTaylorSeries(EI,sym,x0)  := retract(taylor(ex, equation(sym::EI, x0)))$AnyFunctions1(UnivariateTaylorSeries(EI, sym, x0));
    --local approx := approximate(test,3 :: NonNegativeInteger)$UnivariateTaylorSeries(EI,sym,x0);
    1
};

};
---- SNIP ----

Is there a way to completely erase a package from the interpreter environment? For example, even after a ")clear completely", ")show TaylorPackage" still shows that this domain is "available". Sometimes it seems that I have to recompile/load packages twice or restart FriCAS, especially after a type signature has changed (that is even after ")clear completely").

Is there a noticeable performance difference between SPAD and Aldor compiled programs? I'm surprised that for the small test code I have written the generated Lisp code is several times smaller with SPAD. Maybe there is a lot of "auxiliary" code generated with Aldor that isn't involved or used, but if there is a real factor of ~5-10 overhead, it's something to think about.

Thanks,
Tobias

Ralf Hemmecke

unread,
Feb 4, 2021, 5:10:31 PM2/4/21
to fricas-devel
Hi Tobias,

sorry, but I don't go over your code until you give a concrete example
input and tell me what you want to get out.

Small steps please.

Your Aldor program is not helpful and I don't believe that you would
learn anything when we turn it into a program that the Aldor compiler
accepts.

I would rather like to help you with writing code from which you can
learn. But for that I need a specification (at least a starting one).

Ralf

Waldek Hebisch

unread,
Feb 4, 2021, 7:52:03 PM2/4/21
to fricas...@googlegroups.com
On Thu, Feb 04, 2021 at 10:08:53AM -0800, Tobias Neumann wrote:
> Dear FriCAS group,
>
> thinking about writing in Aldor instead of SPAD (to have better error
> messages and maybe less quirks) I came across a few issues. As an example I
> want to (again) write a wrapper over Taylor series with a subsequent
> 'approximate' (see code below).
>
> There seems to be an issue finding 'approximate' from
> UnivariateTaylorSeries (available through UnivariatePowerSeriesCategory):
> [L32 C62] #1 (Error) There are no suitable meanings for the operator
> `approximate$UnivariateTaylorSeries(Expression(Integer), sym, x...'.
>
> I was thinking that this might likely be the same issue as with SPAD, that
> is I have to check whether Expression(Integer) has the approriate 'coerce'
> and '^' operations. Unfortunately this does not seem solve the problem, and
> with the additional conditions as below 'taytest' is also no longer exposed.

This may be the same issue: when calling FriCAS functions Aldor
uses type information extracted from FriCAS. In principle
single reasom may lead to failure in FriCAS and to wrong info
(hence failure) in Aldor. However, Aldor seem to be smart
enough to notice that there are no free parameters and
consequently that runtime test "can not" give different
value than compile time test.
>
> Is there a way to completely erase a package from the interpreter
> environment? For example, even after a ")clear completely", ")show
> TaylorPackage" still shows that this domain is "available". Sometimes it
> seems that I have to recompile/load packages twice or restart FriCAS,
> especially after a type signature has changed (that is even after ")clear
> completely").

ATM there is no way. You can partially hide a package (or
domain) using ')unexpose'. In principle implementing erase
for packages is easy, but careless use of erase could lead to
strange results because there is a lot of dependencies
between constructors and current code assumes checks were
done at compiler time. To give you a taste of possible
problems look at:

(2) -> )unexpose Equation
Equation is now explicitly hidden in frame frame1
(2) -> 1 = 2
There are 2 exposed and 1 unexposed library operations named
equation having 2 argument(s) but none was determined to be
applicable. Use HyperDoc Browse, or issue
)display op equation
to learn more about the available operations. Perhaps
package-calling the operation or using coercions on the arguments
will allow you to apply the operation.

Cannot find a definition or applicable library operation named
equation with argument type(s)
PositiveInteger
PositiveInteger

Perhaps you should use "@" to indicate the required return type,
or "$" to specify which version of the function you need.

At first glance 'equation' above makes no sense, but interpreter
has hardcoded info about 'Equation' and converts '=' to 'equation'
without checking if 'Equation' is exposed.

Basically, when there are dependencies between domains erasing
one should erase all domains depending on it. But FriCAS does
not track dependencies, so it would need to erase all, that is
perform a restart. Alternatively, instead of really erasing
domains one could try to partially hide them, so that explicit
references would fail but dependencies would still work.
As you can see from 'equation' above hiding domains without
bad effects also is not that easy.

> Is there a noticeable performance difference between SPAD and Aldor
> compiled programs? I'm surprised that for the small test code I have
> written the generated Lisp code is several times smaller with SPAD. Maybe
> there is a lot of "auxiliary" code generated with Aldor that isn't involved
> or used, but if there is a real factor of ~5-10 overhead, it's something to
> think about.

Pure Aldor code should be faster than FriCAS code (assuming
you crank up Aldor optimization settings). However, when calling
FriCAS code from Aldor expect worse performance than Spad: FriCAS
code is a black box to Aldor while Spad compiler sees the code
and can perform some optimizations. Size of generated Lisp may
be misleading, better look as size of .fasl file (which contains
actual machine code).

--
Waldek Hebisch

Tobias Neumann

unread,
Feb 16, 2021, 6:36:33 PM2/16/21
to FriCAS - computer algebra system
After using SPAD for a while now, I think I've come across a few
compiler issues, leading either to compilation failure or to programs that crash ("system error").
In all cases I was able to circumvent them by rewriting the expression, interchanging independent lines etc.
One "system error" was for example produced by using
monomial(1,0)$UnivariateTaylorSeries(Expression(Integer),'x,0)
in a longer expression and I was able to circumvent this by just using
1$UnivariateTaylorSeries(Expression(Integer),'x,0)

Ideally I should probably produce minimal working examples and put them on the bugtracker,
but I think some of these just occur when the code is sufficiently complex. I know that there is
little manpower to fix these things, but it might still be worth to collect the issues? Things like this
make me a little nervous about investing development time. What happens when I come across
something without a workaround or there is a very deep and subtle bug? I know that in the end
this is my risk to take, but from your point of view, how concerned should I be? FriCAS/Axiom
have been around for a while and used for hundreds of packages, so I'm probably too concerned.

Have there been thoughts or plans of porting the FriCAS SPAD code completely to Aldor? As far
as I can tell Aldor is unmaintained, so this might not be a good idea in the long run.

The most problematic issue for me right now is that using ")compile file.spad" multiple times
without ")clear all" in-between will completely break things. For example something like:

)co mypackage
test := sqrt(x)
subst(test, x=0)

gives sqrt(0) as it should, but once I use )co mypackage again
it no longer substitutes x=0 and just returns sqrt(x). This then completely breaks the functionality in the package.
A fix for this is to use ")clear all" in between, or to redefine test. Is this "intended" or known behavior? I've had
similar issues before where ")clear completely" was necessary.

I've been able to produce a somewhat minimal example for this particular issue (see test.input and ptest.spad below):

)read test.input
test := sqrt(x)
subst(test,x=0) -- works

)co ptest
subst(test,x=0) -- fails

(Yes the matrix definition in test.input is necessary for this bug to happen)

Thanks and best wishes,
Tobias


ptest.spad:

 )abbrev package EMPTY EmptyPackage 
EmptyPackage() : Exports == Implementation where
    Exports == with
        ident: Integer -> Integer

    Implementation ==> add
        ident(x) == x


test.input:

)clear all
 
)compile ptest.spad 

amat := matrix [[0, 0, 0, 0, 0, 0, 0, 0, 0], [x1/(sqrt(-(t*x1))*sqrt(4 - t*x1)), -(x1/(-4 + t*x1)), 0, 0, 0, 0, 0, 0,  _
  0], [(sqrt(-(t*x3))*sqrt(4 - t*x3))/(t*(-4 + t*x3)), 0, -(x3/(-4 + t*x3)), 0, 0, 0, 0, 0, 0],  _
 [(sqrt(-(t*x2))*sqrt(4 - t*x2))/(t*(-4 + t*x2)), 0, 0, -(x2/(-4 + t*x2)), 0, 0, 0, 0, 0],  _
 [0, 0, (t*x3^2)/((-(t*x3))^(3/2)*sqrt(4 - t*x3)), 0, 0, 0, 0, 0, 0],  _
 [0, (t*x1^2)/((-(t*x1))^(3/2)*sqrt(4 - t*x1)), 0, 0, 0, 0, 0, 0, 0],  _
 [0, 0, x3/(sqrt(-(t*x3))*sqrt(4 - t*x3)), (t*x2^2)/((-(t*x2))^(3/2)*sqrt(4 - t*x2)), 0, 0, 0, 0, 0],  _
 [0, x1/(sqrt(-(t*x1))*sqrt(4 - t*x1)), 0, (t*x2^2)/((-(t*x2))^(3/2)*sqrt(4 - t*x2)), 0, 0, 0, 0, 0],  _
 [0, (2*(-4 + t*x1)*x3)/(sqrt(4 - t*x1)*sqrt(-(t*x3))*sqrt(t*(-4*x1 + 4*x2 - 4*x3 + t*x1*x3))) -  _
   (2*(-4 + t*x1)*x2*sqrt(-(t*x3)))/(t*sqrt(4 - t*x1)*(x1 - x2)* _
     sqrt(t*(-4*x1 + 4*x2 - 4*x3 + t*x1*x3))) + (2*x1*(-4 + t*x2)*sqrt(-(t*x3)))/ _
    (t*sqrt(4 - t*x1)*(x1 - x2)*sqrt(t*(-4*x1 + 4*x2 - 4*x3 + t*x1*x3))),  _
  (2*sqrt(-(t*x1))*(-4 + t*x2)*x3)/(t*(-x2 + x3)*sqrt(4 - t*x3)* _
     sqrt(t*(-4*x1 + 4*x2 - 4*x3 + t*x1*x3))) - (2*x1*sqrt(4 - t*x3))/ _
    (sqrt(-(t*x1))*sqrt(t*(-4*x1 + 4*x2 - 4*x3 + t*x1*x3))) - (2*sqrt(-(t*x1))*x2*(-4 + t*x3))/ _
    (t*(-x2 + x3)*sqrt(4 - t*x3)*sqrt(t*(-4*x1 + 4*x2 - 4*x3 + t*x1*x3))),  _
  (-2*sqrt(-(t*x1))*x2*(-4 + t*x2)*x3)/(sqrt(-(t*x2))*sqrt(4 - t*x2)*(x2 - x3)*sqrt(-(t*x3))* _
     sqrt(t*(-4*x1 + 4*x2 - 4*x3 + t*x1*x3))) + (2*x1*sqrt(-(t*x2))*sqrt(4 - t*x2)*sqrt(-(t*x3)))/ _
    (t*sqrt(-(t*x1))*(x1 - x2)*sqrt(t*(-4*x1 + 4*x2 - 4*x3 + t*x1*x3))) -  _
   (2*sqrt(-(t*x1))*(4*x1*x2*sqrt(-(t*x3)) - 8*x2^2*sqrt(-(t*x3)) + t*x2^3*sqrt(-(t*x3)) +  _
      4*x2*x3*sqrt(-(t*x3)) - t*x1*x2*x3*sqrt(-(t*x3))))/(t*sqrt(-(t*x2))*(-x1 + x2)*sqrt(4 - t*x2)* _
     (x2 - x3)*sqrt(t*(-4*x1 + 4*x2 - 4*x3 + t*x1*x3))),  _
  (sqrt(-(t*x1))*(x1 - x2)*sqrt(-(t*x3)))/(t*(x1 - x2 + x3)*sqrt(t*(-4*x1 + 4*x2 - 4*x3 + t*x1*x3))) -  _
   (sqrt(-(t*x1))*x2*(-(t*x3))^(3/2))/(t^2*x3*(x1 - x2 + x3)*sqrt(t*(-4*x1 + 4*x2 - 4*x3 + t*x1*x3))) -  _
   (x1*sqrt(-(t*x3))*(-x2 + x3))/(sqrt(-(t*x1))*(x1 - x2 + x3)*sqrt(t*(-4*x1 + 4*x2 - 4*x3 + t*x1*x3))),  _
  (sqrt(-(t*x1))*(x1 - x2)*sqrt(-(t*x3)))/(t*(x1 - x2 + x3)*sqrt(t*(-4*x1 + 4*x2 - 4*x3 + t*x1*x3))) -  _
   (sqrt(-(t*x1))*x2*(-(t*x3))^(3/2))/(t^2*x3*(x1 - x2 + x3)*sqrt(t*(-4*x1 + 4*x2 - 4*x3 + t*x1*x3))) -  _
   (x1*sqrt(-(t*x3))*(-x2 + x3))/(sqrt(-(t*x1))*(x1 - x2 + x3)*sqrt(t*(-4*x1 + 4*x2 - 4*x3 + t*x1*x3))),  _
  -((sqrt(-(t*x1))*(x1 - x2)*sqrt(-(t*x3)))/(t*(x1 - x2 + x3)*sqrt(t*(-4*x1 + 4*x2 - 4*x3 + t*x1*x3)))) +  _
   (sqrt(-(t*x1))*x2*(-(t*x3))^(3/2))/(t^2*x3*(x1 - x2 + x3)*sqrt(t*(-4*x1 + 4*x2 - 4*x3 + t*x1*x3))) +  _
   (x1*sqrt(-(t*x3))*(-x2 + x3))/(sqrt(-(t*x1))*(x1 - x2 + x3)*sqrt(t*(-4*x1 + 4*x2 - 4*x3 + t*x1*x3))),  _
  (sqrt(-(t*x1))*x2*sqrt(-(t*x3)))/(t*(-x1 + x2 - x3)*sqrt(t*(-4*x1 + 4*x2 - 4*x3 + t*x1*x3))) +  _
   (sqrt(-(t*x1))*(x1 - x2)*x3)/(sqrt(-(t*x3))*(x1 - x2 + x3)*sqrt(t*(-4*x1 + 4*x2 - 4*x3 + t*x1*x3))) +  _
   (x1*sqrt(-(t*x3))*(-x2 + x3))/(sqrt(-(t*x1))*(x1 - x2 + x3)*sqrt(t*(-4*x1 + 4*x2 - 4*x3 + t*x1*x3))),  _
  (x1*x2*x3)/((-x1 + x2 - x3)*(-4*x1 + 4*x2 - 4*x3 + t*x1*x3)) -  _
   ((x1^2 - x1*x2)*x3)/((x1 - x2 + x3)*(-4*x1 + 4*x2 - 4*x3 + t*x1*x3)) -  _
   (x1*x3*(-x2 + x3))/((x1 - x2 + x3)*(-4*x1 + 4*x2 - 4*x3 + t*x1*x3))]]

Waldek Hebisch

unread,
Feb 17, 2021, 7:41:09 PM2/17/21
to fricas...@googlegroups.com
On Tue, Feb 16, 2021 at 03:36:33PM -0800, Tobias Neumann wrote:
>
> >
> > After using SPAD for a while now, I think I've come across a few
> > compiler issues, leading either to compilation failure or to programs that
> > crash ("system error").
> > In all cases I was able to circumvent them by rewriting the expression,
> > interchanging independent lines etc.
> > One "system error" was for example produced by using
> > monomial(1,0)$UnivariateTaylorSeries(Expression(Integer),'x,0)
> > in a longer expression and I was able to circumvent this by just using
> > 1$UnivariateTaylorSeries(Expression(Integer),'x,0)
> >
> > Ideally I should probably produce minimal working examples and put them on
> > the bugtracker,
> > but I think some of these just occur when the code is sufficiently
> > complex. I know that there is
> > little manpower to fix these things, but it might still be worth to
> > collect the issues?

I must admit that when I work on Spad code I often go with workaround
intead of trying to investigate and fix compiler bug. So if
do not produce examples I will understand. OTOH testcases are
useful. Even testcase for known problem may be quite useful,
as it may give new info.

> Things like this
> > make me a little nervous about investing development time. What happens
> > when I come across
> > something without a workaround or there is a very deep and subtle bug? I
> > know that in the end
> > this is my risk to take, but from your point of view, how concerned should
> > I be? FriCAS/Axiom
> > have been around for a while and used for hundreds of packages, so I'm
> > probably too concerned.

I do not think you should be very concerned. Many problems are visible
due to static typing and those show very early. And while not fast
bugs do get fixed.

> > Have there been thoughts or plans of porting the FriCAS SPAD code
> > completely to Aldor? As far
> > as I can tell Aldor is unmaintained, so this might not be a good idea in
> > the long run.

There were plans in early period of open source Axiom. AFAIK there are
no visible results. There would be some benefit if one could compile
algebra using Aldor. Relatively recently I did a little experiment
and it seems that there is a lot of use of few constructs that are valid
and perfectly good Spad but which are rejected by Aldor. IMO if one
seriously thinks about using Aldor to compile FriCAS algebra one
first needs to modify Aldor to accept those constructs. Also,
on files that I tried Aldor compiler was about 10 times slower than
Spad compiler. For me Spad compiler is slow and 10 times slowdown
would be step back.

> > The most problematic issue for me right now is that using ")compile
> > file.spad" multiple times
> > without ")clear all" in-between will completely break things. For example
> > something like:
> >
> > )co mypackage
> > test := sqrt(x)
> > subst(test, x=0)
> >
> > gives sqrt(0) as it should, but once I use )co mypackage again
> > it no longer substitutes x=0 and just returns sqrt(x). This then
> > completely breaks the functionality in the package.
> > A fix for this is to use ")clear all" in between, or to redefine test. Is
> > this "intended" or known behavior? I've had
> > similar issues before where ")clear completely" was necessary.

The issue was known, it has almost nothing to do with Spad compiler,
in particular the same should happen when using Aldor from FriCAS.
The core problem is that kernels are supposed to be unique.
Compilation has to invalidate existing domains, to make sure
that new code is used in all places. Kernels are stored in
separate domain called 'SortedCache', invalidating this domain
led to duplicate kernels and chaos. More precisely, there is
support for (at least somewhat) safely invalidating old kernels,
but it was not used. AFAICS attached patch solves your problem.

--
Waldek Hebisch
sum6a.diff

Ralf Hemmecke

unread,
Feb 18, 2021, 2:24:11 AM2/18/21
to fricas...@googlegroups.com
> There were plans in early period of open source Axiom. AFAIK there
> are no visible results. There would be some benefit if one could
> compile algebra using Aldor. Relatively recently I did a little
> experiment and it seems that there is a lot of use of few constructs
> that are valid and perfectly good Spad but which are rejected by
> Aldor. IMO if one seriously thinks about using Aldor to compile
> FriCAS algebra one first needs to modify Aldor to accept those
> constructs.

Waldek, can you give a list of those constructs so that we can show them
publicly in "Differences between Aldor and SPAD"?

> Also, on files that I tried Aldor compiler was about 10 times slower
> than Spad compiler. For me Spad compiler is slow and 10 times
> slowdown would be step back.

That is one issue. But honestly, it is more important to me if the
compiled code runs faster and is safer.

Ralf

Ralf Hemmecke

unread,
Feb 18, 2021, 8:47:45 AM2/18/21
to fricas-devel
>> Have there been thoughts or plans of porting the FriCAS SPAD code
>> completely to Aldor?

That were a good plan. What is missing is manpower.

>> As far as I can tell Aldor is unmaintained, so this might not be a
>> good idea in the long run.

Not completely true. Peter Broadbery is looking into issues, but, of
course, there is also a lack of manpower. It simply took too long to
release Aldor as an open-source project.

Ralf

Waldek Hebisch

unread,
Feb 18, 2021, 12:37:03 PM2/18/21
to fricas...@googlegroups.com
On Thu, Feb 18, 2021 at 08:24:08AM +0100, Ralf Hemmecke wrote:
> > There were plans in early period of open source Axiom. AFAIK there
> > are no visible results. There would be some benefit if one could
> > compile algebra using Aldor. Relatively recently I did a little
> > experiment and it seems that there is a lot of use of few constructs
> > that are valid and perfectly good Spad but which are rejected by
> > Aldor. IMO if one seriously thinks about using Aldor to compile
> > FriCAS algebra one first needs to modify Aldor to accept those
> > constructs.
>
> Waldek, can you give a list of those constructs so that we can show them
> publicly in "Differences between Aldor and SPAD"?

See attached file and Aldor compilation report (I sent it before
but I include it in case it got lost).
>
> > Also, on files that I tried Aldor compiler was about 10 times slower
> > than Spad compiler. For me Spad compiler is slow and 10 times
> > slowdown would be step back.
>
> That is one issue. But honestly, it is more important to me if the
> compiled code runs faster and is safer.

Yes, safer code is among expected benefits. Concerning speed:
AFAIK there is no inlining between Aldor and Spad code. So
if you use Spad types from Aldor (via interface) all operations
would go via function calls and consequently almost all Aldor
optimizations will be ineffective. So you will get better
speed only when all time-critical parts will be pure Aldor.
IIUC in your interface few basic Spad types are entirely replaced
by low Aldor types, but my impression is that Spad compiler
can profitably inline more than that.

--
Waldek Hebisch

Waldek Hebisch

unread,
Feb 18, 2021, 12:38:22 PM2/18/21
to fricas...@googlegroups.com
On Thu, Feb 18, 2021 at 06:36:57PM +0100, Waldek Hebisch wrote:
> See attached file and Aldor compilation report (I sent it before
> but I include it in case it got lost).

Sorry, sent previous message too fast, without attachements.
--
Waldek Hebisch
RDEEFX3a.rapp
RDEEFX3a.as

Peter Broadbery

unread,
Feb 18, 2021, 4:14:20 PM2/18/21
to fricas-devel
I'll take a look at your example; it's possible that there's some
unreleased changes that will help.
Does that test file also show a factor of 10 slowdown?

I had also started a bottom up translation of SPAD to Aldor code, but
stopped for some reason. If any one is interested in resurrecting
this project I'm happy to share it.

Peter



Peter
> --
> You received this message because you are subscribed to the Google Groups "FriCAS - computer algebra system" group.
> To unsubscribe from this group and stop receiving emails from it, send an email to fricas-devel...@googlegroups.com.
> To view this discussion on the web visit https://groups.google.com/d/msgid/fricas-devel/20210218173657.GA12410%40math.uni.wroc.pl.

Ralf Hemmecke

unread,
Feb 18, 2021, 4:32:57 PM2/18/21
to fricas-devel
> Yes, safer code is among expected benefits. Concerning speed: AFAIK
> there is no inlining between Aldor and Spad code.

Yes, THAT is a big problem. I don't know if Peter has a solution for this.

> So if you use Spad types from Aldor (via interface) all operations
> would go via function calls and consequently almost all Aldor
> optimizations will be ineffective.

True. I guess developing addon packages with Aldor will probably only
work nicely, if the whole library is compiled with Aldor including the
bootstrapping process. Not a simple task, methinks.

> So you will get better speed only when all time-critical parts will
> be pure Aldor. IIUC in your interface few basic Spad types are
> entirely replaced by low Aldor types, but my impression is that Spad
> compiler can profitably inline more than that.

Yes certainly. But it would be nice if Aldor had a mode that is as lax
with the type checking as the SPAD compiler and so would the aldor
compiler would be equally fast. I guess only compile time speed would
convince you to switch to Aldor.

I also understand that for development it is important to allow
compilation of a file and including the compiled code it into a running
without having to recompile the whole system.

I see some benefit for the future of FriCAS if its library is fully
compiled with Aldor, because Aldor can also produce libary code that
could be used by other systems. In particular there might be more
interest from the Sage community in using it and perhaps also developing
it. We are still lacking developers. :-(

Ralf

Ralf Hemmecke

unread,
Feb 18, 2021, 6:57:00 PM2/18/21
to fricas-devel
On 18.02.21 18:38, Waldek Hebisch wrote:
> On Thu, Feb 18, 2021 at 06:36:57PM +0100, Waldek Hebisch wrote:
>> See attached file and Aldor compilation report (I sent it before
>> but I include it in case it got lost).

Waldek,

I do not understand why you complain here.

"/mnt/lv3/fricas/axp19/pp1/algreduc2/RDEEFX3a.as", line 36:
ei_int : (Z, F, F, SE) -> PSOL2
......^
[L36 C7] #1 (Warning) Escape character ignored. Do you mean '__'?

Aldor convention is to use CamelCase for identifiers. And that was also
the rule for SPAD code (except for some people that insisted on using
underscores (which had to be written as double underscores).
Then you changed the SPAD compiler with a new rule that allows single
underscores.

I would have liked to stay with CamelCase. Now we have basically two
naming conventions. There are only a few functions now that include an
underscore character (I guess mostly introduced by you). That you now
complain about Aldor throwing errors at you for an incompatibility that
you have introduced is somewhat strange.

There are a number of other issues with your code.

I doubled the underscores.

The problems were mostly forgotten imports. Note that Aldor insists on
importing functions explicitly. Unlike SPAD almost nothing is in scope.

Then there were a few cases where I had to add a qualification, for
example here:

univariate(r1, kx)$F

where the Aldor compiler saw two functions with name "univariate" that
would have been applicable. Without giving some type information it
didn't know what to choose.

The most problematic thing, however was the

Union(CV__REC, 'failed')

construction. I could make it compile with this type

Union(cv:CV__REC, fail:'failed')

Perhaps Peter knows how to make it compile with an untagged union.

One must also put the return value into a "union" explicitly.

BTW, you should use

#include "fricas"

instead of

#include "axiom.as"

=========================
(14) -> )compile RDEEFX3a.as
Compiling FriCAS source code from file
/home/hemmecke/backup/git/qeta/tmp/RDEEFX3a.as using Aldor
compiler and options
-O -Fasy -Fao -Flsp -lfricas -Mno-ALDOR_W_WillObsolete -DFriCAS -Y
$FRICAS/algebra -I $FRICAS/algebra
Use the system command )set compiler args to change these
options.
"/home/hemmecke/HDD/hemmecke/software/lib/fricas/target/x86_64-linux-gnu/algebra/fricas.as",
line 16:
import {
^
[L16 C1] #1 (Warning) Couldn't find identifier for documentation

Compiling Lisp source code from file ./RDEEFX3a.lsp
Issuing )library command for RDEEFX3a
Reading /home/hemmecke/backup/git/qeta/tmp/RDEEFX3a.asy
ElementaryRischDEXY is already explicitly exposed in frame initial
ElementaryRischDEXY will be automatically loaded when needed from
/home/hemmecke/backup/git/qeta/tmp/RDEEFX3a
==========================

What I do not understand is why Aldor gives me this warning. Peter?

Ralf
RDEEFX3a.as

Waldek Hebisch

unread,
Feb 18, 2021, 7:25:32 PM2/18/21
to fricas...@googlegroups.com
On Fri, Feb 19, 2021 at 12:56:58AM +0100, Ralf Hemmecke wrote:
> On 18.02.21 18:38, Waldek Hebisch wrote:
> > On Thu, Feb 18, 2021 at 06:36:57PM +0100, Waldek Hebisch wrote:
> >> See attached file and Aldor compilation report (I sent it before
> >> but I include it in case it got lost).
>
> Waldek,
>
> I do not understand why you complain here.
>
> "/mnt/lv3/fricas/axp19/pp1/algreduc2/RDEEFX3a.as", line 36:
> ei_int : (Z, F, F, SE) -> PSOL2
> ......^
> [L36 C7] #1 (Warning) Escape character ignored. Do you mean '__'?
>
> Aldor convention is to use CamelCase for identifiers. And that was also
> the rule for SPAD code (except for some people that insisted on using
> underscores (which had to be written as double underscores).
> Then you changed the SPAD compiler with a new rule that allows single
> underscores.
>
> I would have liked to stay with CamelCase. Now we have basically two
> naming conventions. There are only a few functions now that include an
> underscore character (I guess mostly introduced by you). That you now
> complain about Aldor throwing errors at you for an incompatibility that
> you have introduced is somewhat strange.

This is just a warning, in first pass of checking Spad code we
probably can ignore warnings. OTOH this is important feature
for mixed-language code. In Lisp camelCase is not practical,
dashes that Lispers use are illegal in other languages, so
only sane choice is to use underscores.

> There are a number of other issues with your code.
>
> I doubled the underscores.
>
> The problems were mostly forgotten imports. Note that Aldor insists on
> importing functions explicitly. Unlike SPAD almost nothing is in scope.

Yes, I know this. One point of this excercise was to see how many
explicit imports I would need. It was disappointing that other
problems apparently dwarfed issue with imports.

> Then there were a few cases where I had to add a qualification, for
> example here:
>
> univariate(r1, kx)$F
>
> where the Aldor compiler saw two functions with name "univariate" that
> would have been applicable. Without giving some type information it
> didn't know what to choose.
>
> The most problematic thing, however was the
>
> Union(CV__REC, 'failed')
>
> construction.

IIUC Aldor does not suport "failed" (with Spad notation) as a type,
which leads to massive source changes (this is in the language
differences page).

> I could make it compile with this type
>
> Union(cv:CV__REC, fail:'failed')
>
> Perhaps Peter knows how to make it compile with an untagged union.
>
> One must also put the return value into a "union" explicitly.

--
Waldek Hebisch

Ralf Hemmecke

unread,
Feb 19, 2021, 4:48:02 AM2/19/21
to fricas...@googlegroups.com
>> "/mnt/lv3/fricas/axp19/pp1/algreduc2/RDEEFX3a.as", line 36:
>> ei_int : (Z, F, F, SE) -> PSOL2
>> ......^
>> [L36 C7] #1 (Warning) Escape character ignored. Do you mean '__'?
>>
> This is just a warning, in first pass of checking Spad code we
> probably can ignore warnings.

Ooops. Yes, indeed. However, it gives different identifiers in Aldor and
SPAD. In Aldor ei_int is the same as eiint.

> OTOH this is important feature
> for mixed-language code. In Lisp camelCase is not practical,

From primitives.lisp ...

(defun |STR_to_CHAR_fun| (s)

As far as I understand it would be perfectly fine to use |CamelCase|
identifiers in Lisp. So, yes, I agree that there are different naming
conventions in Lisp and Aldor/SPAD, but I don't think that in a
multi-language system (where one language (SPAD) is the main language
and all the others are helper languages that implement the underlying
system)
one must unify the naming conventions.

That said, yes, let's ignore the underscore warnings in an approach to
bring the full library to Aldor.

> Yes, I know this. One point of this excercise was to see how many
> explicit imports I would need. It was disappointing that other
> problems apparently dwarfed issue with imports.

One way to avoid most of the explicit imports is to always add the type
to a variable when you first assign it.
That has two (at least for me) important aspects.

(1) Readers of the code explicitly see what the type of the variable is
and don't have to figure it out from the context --- that's sometimes
not so easy. (Maybe that can some day be relaxed, if we have editors
that show the type of an expression when your mouse hovers over it.)

(2) In Aldor 'a: A' means also an implicit 'import from A'. Aldor has :*
for avoiding this implicit import. See Section 8.13 of the Aldor User Guide.

If there is too much in scope one has to help the compiler in certain
places to disambiguate function calls with the same name and argument
types. But that is easy with $ and @. Actually, Aldor is quite good in
selecting the right function if it can figure out enough type
information from the context.

> IIUC Aldor does not suport "failed" (with Spad notation) as a type,
> which leads to massive source changes (this is in the language
> differences page).

Yes, true. Honestly, I don't like "failed" or Union(X, "failed") very
much. (In particular the double quotes are confusing.) I better liked
the Partial(X) construction in the Aldor library. And certainly such
Partial domain can be programmed and used in SPAD that's not a big deal.
So we could slowly replace Union(X,"failed") by Parial(X) and still have
running SPAD code.

Furthermore, in you code I had to replace

for k in rest(lk) repeat
...
is?(tk, EXP) => "iterate"
...

for k in rest(lk) repeat
...
is?(tk, EXP) => iterate
...

The error message

"/home/hemmecke/backup/git/qeta/tmp/RDEEFX3a.as", line 80:
is?(tk, EXP) => "iterate"
............................^
[L80 C29] #2 (Error) (After Macro Expansion) Have determined 2 possible
types for the expression.
Meaning 1: Symbol
Meaning 2: String
Expanded expression was: "iterate"

does not explicitly say why this is a problem, but I guess it is,
because Aldor want ONE type for the block following the 'repeat' keyword.

Ralf

Peter Broadbery

unread,
Feb 21, 2021, 12:53:52 PM2/21/21
to fricas-devel
On Fri, 19 Feb 2021 at 09:48, Ralf Hemmecke <ra...@hemmecke.org> wrote:
>
> >> "/mnt/lv3/fricas/axp19/pp1/algreduc2/RDEEFX3a.as", line 36:
> >> ei_int : (Z, F, F, SE) -> PSOL2
> >> ......^
> >> [L36 C7] #1 (Warning) Escape character ignored. Do you mean '__'?
> >>
> > This is just a warning, in first pass of checking Spad code we
> > probably can ignore warnings.
>
> Ooops. Yes, indeed. However, it gives different identifiers in Aldor and
> SPAD. In Aldor ei_int is the same as eiint.
>

This has always struck me as a bit of a misfeature; It may be better
if the lexer was
modified to treat '_' as a normal character within identifiers.

> > OTOH this is important feature
> > for mixed-language code. In Lisp camelCase is not practical,
>
> From primitives.lisp ...
>
> (defun |STR_to_CHAR_fun| (s)
>
> As far as I understand it would be perfectly fine to use |CamelCase|
> identifiers in Lisp. So, yes, I agree that there are different naming
> conventions in Lisp and Aldor/SPAD, but I don't think that in a
> multi-language system (where one language (SPAD) is the main language
> and all the others are helper languages that implement the underlying
> system)
> one must unify the naming conventions.
>
> That said, yes, let's ignore the underscore warnings in an approach to
> bring the full library to Aldor.
>
> > Yes, I know this. One point of this excercise was to see how many
> > explicit imports I would need. It was disappointing that other
> > problems apparently dwarfed issue with imports.
>
> One way to avoid most of the explicit imports is to always add the type
> to a variable when you first assign it.
> That has two (at least for me) important aspects.
>
> (1) Readers of the code explicitly see what the type of the variable is
> and don't have to figure it out from the context --- that's sometimes
> not so easy. (Maybe that can some day be relaxed, if we have editors
> that show the type of an expression when your mouse hovers over it.)
>

We are potentially quite close to this for Aldor - a lot of the groundwork
has been done, but not there yet.

> (2) In Aldor 'a: A' means also an implicit 'import from A'. Aldor has :*
> for avoiding this implicit import. See Section 8.13 of the Aldor User Guide.
>
> If there is too much in scope one has to help the compiler in certain
> places to disambiguate function calls with the same name and argument
> types. But that is easy with $ and @. Actually, Aldor is quite good in
> selecting the right function if it can figure out enough type
> information from the context.
>
> > IIUC Aldor does not suport "failed" (with Spad notation) as a type,
> > which leads to massive source changes (this is in the language
> > differences page).
>

Aldor does allow 'Union(a: T, failed?: 'failed'), which might be similar enough.
Tangentially, what would be the issues with switching the algebra code to use
Partial instead of the Union?


Peter

Ralf Hemmecke

unread,
Feb 21, 2021, 2:19:13 PM2/21/21
to fricas...@googlegroups.com


On 21.02.21 18:53, Peter Broadbery wrote:
> On Fri, 19 Feb 2021 at 09:48, Ralf Hemmecke <ra...@hemmecke.org> wrote:
>>
>>>> "/mnt/lv3/fricas/axp19/pp1/algreduc2/RDEEFX3a.as", line 36:
>>>> ei_int : (Z, F, F, SE) -> PSOL2
>>>> ......^
>>>> [L36 C7] #1 (Warning) Escape character ignored. Do you mean '__'?
>>>>
>>> This is just a warning, in first pass of checking Spad code we
>>> probably can ignore warnings.
>>
>> Ooops. Yes, indeed. However, it gives different identifiers in Aldor and
>> SPAD. In Aldor ei_int is the same as eiint.
>>
>
> This has always struck me as a bit of a misfeature; It may be better
> if the lexer was
> modified to treat '_' as a normal character within identifiers.

BTW, I never said that I like double underscores in identifiers. I just
think that we should rather stick with using CamelCase identifiers in
Aldor/SPAD code and not being driven by naming conventions in other
languages (neither Lisp nor C).

If you like then change the Aldor lexer. I find it then just a little
annoying that the underscore is no longer an escape character in all
situations.

Long time ago I also heard Stephen Watt thinking aloud to change the
escape character from underscore to something else. I would also be open
to that, but have no good suggestion for another escape character.
There are, however identifiers like ts_v_+ in FriCAS or mod_+ in Aldor,
that rely on _ being an escape character and would probably look strange
with another escape character.

The backslash would be fine if we didn't have identifiers like /\ and
\/. However, if the character set for identifiers would be extended to
unicode, then backslash would be OK. Unicode identifiers would also
allow for more operation symbols like

Unicode Character 'CIRCLED PLUS' (U+2295).

and more. (Well... hopefully that doesn't start the discussion about
SemiGroup vs. AbelianSemiGroup again.)


>> One way to avoid most of the explicit imports is to always add the type
>> to a variable when you first assign it.
>> That has two (at least for me) important aspects.
>>
>> (1) Readers of the code explicitly see what the type of the variable is
>> and don't have to figure it out from the context --- that's sometimes
>> not so easy. (Maybe that can some day be relaxed, if we have editors
>> that show the type of an expression when your mouse hovers over it.)

Peter, that would be great, but I fear that doesn't make everyone happy
since it requires a certain editor with your plugin, right?

>>> IIUC Aldor does not suport "failed" (with Spad notation) as a type,
>>> which leads to massive source changes (this is in the language
>>> differences page).

> Aldor does allow 'Union(a: T, failed?: 'failed'), which might be similar enough.
> Tangentially, what would be the issues with switching the algebra code to use
> Partial instead of the Union?

I would love to see such a change and I would happily help in this
endeavour.

Ralf
Ralf

Peter Broadbery

unread,
Feb 21, 2021, 5:36:24 PM2/21/21
to fricas-devel
On Sun, 21 Feb 2021 at 19:19, Ralf Hemmecke <ra...@hemmecke.org> wrote:
>
>
>
> On 21.02.21 18:53, Peter Broadbery wrote:
> > On Fri, 19 Feb 2021 at 09:48, Ralf Hemmecke <ra...@hemmecke.org> wrote:
> >>
> >>>> "/mnt/lv3/fricas/axp19/pp1/algreduc2/RDEEFX3a.as", line 36:
> >>>> ei_int : (Z, F, F, SE) -> PSOL2
> >>>> ......^
> >>>> [L36 C7] #1 (Warning) Escape character ignored. Do you mean '__'?
> >>>>
> >>> This is just a warning, in first pass of checking Spad code we
> >>> probably can ignore warnings.
> >>
> >> Ooops. Yes, indeed. However, it gives different identifiers in Aldor and
> >> SPAD. In Aldor ei_int is the same as eiint.
> >>
> >
> > This has always struck me as a bit of a misfeature; It may be better
> > if the lexer was
> > modified to treat '_' as a normal character within identifiers.
>
> BTW, I never said that I like double underscores in identifiers. I just
> think that we should rather stick with using CamelCase identifiers in
> Aldor/SPAD code and not being driven by naming conventions in other
> languages (neither Lisp nor C).
>
> If you like then change the Aldor lexer. I find it then just a little
> annoying that the underscore is no longer an escape character in all
> situations.
>

The plan would be that the underscore would only be an escape character
within an identifier if it changed the treatment of the following character.
So _+ would be an identifier called '+', mod_+ would be 'mod+' (as today),
but foo_bar would be 'foo_bar'. Calls to lisp hyphenated names would still
need underscores, so 'read_-byte', etc

> Long time ago I also heard Stephen Watt thinking aloud to change the
> escape character from underscore to something else. I would also be open
> to that, but have no good suggestion for another escape character.
> There are, however identifiers like ts_v_+ in FriCAS or mod_+ in Aldor,
> that rely on _ being an escape character and would probably look strange
> with another escape character.
>
> The backslash would be fine if we didn't have identifiers like /\ and
> \/. However, if the character set for identifiers would be extended to
> unicode, then backslash would be OK. Unicode identifiers would also
> allow for more operation symbols like
>
> Unicode Character 'CIRCLED PLUS' (U+2295).
>
> and more. (Well... hopefully that doesn't start the discussion about
> SemiGroup vs. AbelianSemiGroup again.)
>
>
> >> One way to avoid most of the explicit imports is to always add the type
> >> to a variable when you first assign it.
> >> That has two (at least for me) important aspects.
> >>
> >> (1) Readers of the code explicitly see what the type of the variable is
> >> and don't have to figure it out from the context --- that's sometimes
> >> not so easy. (Maybe that can some day be relaxed, if we have editors
> >> that show the type of an expression when your mouse hovers over it.)
>
> Peter, that would be great, but I fear that doesn't make everyone happy
> since it requires a certain editor with your plugin, right?
>

The certain editor would be intellij. I like it, at least for certain
types of work. Others
will have other opinions, and as with vi & emacs, each to their own.

> >>> IIUC Aldor does not suport "failed" (with Spad notation) as a type,
> >>> which leads to massive source changes (this is in the language
> >>> differences page).
>
> > Aldor does allow 'Union(a: T, failed?: 'failed'), which might be similar enough.
> > Tangentially, what would be the issues with switching the algebra code to use
> > Partial instead of the Union?
>
> I would love to see such a change and I would happily help in this
> endeavour.
>
> Ralf
> Ralf
>
> --
> You received this message because you are subscribed to the Google Groups "FriCAS - computer algebra system" group.
> To unsubscribe from this group and stop receiving emails from it, send an email to fricas-devel...@googlegroups.com.
> To view this discussion on the web visit https://groups.google.com/d/msgid/fricas-devel/7fee7312-a143-8cf9-92d2-b194e30d2e10%40hemmecke.org.

Qian Yun

unread,
Feb 22, 2021, 9:03:39 PM2/22/21
to fricas...@googlegroups.com
I would like FriCAS to move away from "failed" and choose Haskell style
"Maybe" instead. This topic has been discussed before, I wonder if
Waldek's opinion has changed.

- Qian

Waldek Hebisch

unread,
Feb 23, 2021, 12:24:42 PM2/23/21
to fricas...@googlegroups.com
On Sun, Feb 21, 2021 at 05:53:24PM +0000, Peter Broadbery wrote:
> >
> > > IIUC Aldor does not suport "failed" (with Spad notation) as a type,
> > > which leads to massive source changes (this is in the language
> > > differences page).
> >
>
> Aldor does allow 'Union(a: T, failed?: 'failed'), which might be similar enough.
> Tangentially, what would be the issues with switching the algebra code to use
> Partial instead of the Union?

Well, I do not know what Partial offers. In particular, what we
gain from using Partial instead of Union. Concerning "failed"
and similar, it is not only Union(T, "failed"). One can have
multiple alternatives or multiple failure modes.

If we replace Union(T, "failed") by something else we would
handle most cases of such types. Some other could be converted
to Enumeration. OTOH, talking abtractly Spad has notion
of singleton types: types with only one value. Such types
seem to be useful and Spad notation (as a string) looks reasonable.
It is not clear for me what we gain by eradicating such
types (or at least current notation for such types) from
the language.

--
Waldek Hebisch

Waldek Hebisch

unread,
Feb 23, 2021, 1:00:23 PM2/23/21
to fricas...@googlegroups.com
Up to now I saw nothing to change my opinion. To clarify, automatic
"lifting" of operations for T to say Maybe(T) would be useful.
But up to now I do not see workable proposal how to implement
such lifting and what exact rules should be. Without viable
strategy for implementing extra functionality change to
Maybe from my point of view looks pointless.

To put is differenly, I view compiler, language and coding idioms
as a whole. Clearly many language constructs need compiler
support. Coding idioms depend on language and compiler.
New coding idiom my be quite useful without new support.
But IMO usefulness of Maybe depends very much on features
of Haskell and Haskell compiler. While it may be
possible to have useful effect is quite different way,
mere change of notation does not look useful.

--
Waldek Hebisch

Peter Broadbery

unread,
Feb 23, 2021, 2:31:16 PM2/23/21
to fricas-devel
OK - That does make sense. I do have some ideas for how automatic
lifting can be
done within Aldor, but it looks like there are a lot of other issues
to work through as well.

> --
> Waldek Hebisch
>
> --
> You received this message because you are subscribed to the Google Groups "FriCAS - computer algebra system" group.
> To unsubscribe from this group and stop receiving emails from it, send an email to fricas-devel...@googlegroups.com.
> To view this discussion on the web visit https://groups.google.com/d/msgid/fricas-devel/20210223180017.GB15427%40math.uni.wroc.pl.

Qian Yun

unread,
Feb 24, 2021, 5:13:22 AM2/24/21
to fricas...@googlegroups.com


On 2/24/21 2:00 AM, Waldek Hebisch wrote:
> On Tue, Feb 23, 2021 at 10:03:25AM +0800, Qian Yun wrote:
>>
>> I would like FriCAS to move away from "failed" and choose Haskell style
>> "Maybe" instead. This topic has been discussed before, I wonder if
>> Waldek's opinion has changed.
>
> Up to now I saw nothing to change my opinion. To clarify, automatic
> "lifting" of operations for T to say Maybe(T) would be useful.

Why would that be useful? I think explicit type conversion is
better than implicit/automatic type conversion.

> But up to now I do not see workable proposal how to implement
> such lifting and what exact rules should be. Without viable
> strategy for implementing extra functionality change to
> Maybe from my point of view looks pointless.
>
> To put is differenly, I view compiler, language and coding idioms
> as a whole. Clearly many language constructs need compiler
> support. Coding idioms depend on language and compiler.
> New coding idiom my be quite useful without new support.
> But IMO usefulness of Maybe depends very much on features
> of Haskell and Haskell compiler. While it may be
> possible to have useful effect is quite different way,
> mere change of notation does not look useful.
>

I think in Haskell, "Maybe" is purely implemented as library
and requires zero compiler support.

- Qian

Waldek Hebisch

unread,
Feb 24, 2021, 7:45:07 AM2/24/21
to fricas...@googlegroups.com
On Wed, Feb 24, 2021 at 06:12:45PM +0800, Qian Yun wrote:
>
>
> On 2/24/21 2:00 AM, Waldek Hebisch wrote:
> > On Tue, Feb 23, 2021 at 10:03:25AM +0800, Qian Yun wrote:
> > >
> > > I would like FriCAS to move away from "failed" and choose Haskell style
> > > "Maybe" instead. This topic has been discussed before, I wonder if
> > > Waldek's opinion has changed.
> >
> > Up to now I saw nothing to change my opinion. To clarify, automatic
> > "lifting" of operations for T to say Maybe(T) would be useful.
>
> Why would that be useful? I think explicit type conversion is
> better than implicit/automatic type conversion.

It is really about automatically generating boilerplate code.
If you do not want what Haskell offers and prefer to write
code by hand, then I do not understand why you want Maybe.

> > But up to now I do not see workable proposal how to implement
> > such lifting and what exact rules should be. Without viable
> > strategy for implementing extra functionality change to
> > Maybe from my point of view looks pointless.
> >
> > To put is differenly, I view compiler, language and coding idioms
> > as a whole. Clearly many language constructs need compiler
> > support. Coding idioms depend on language and compiler.
> > New coding idiom my be quite useful without new support.
> > But IMO usefulness of Maybe depends very much on features
> > of Haskell and Haskell compiler. While it may be
> > possible to have useful effect is quite different way,
> > mere change of notation does not look useful.
> >
>
> I think in Haskell, "Maybe" is purely implemented as library
> and requires zero compiler support.

I admit that my understandin of Maybe is rather shallow,
so please correct me if I am wrong. However I think:
- Maybe is implementd by library
- Maybe depends on language/compiler support is sense that
similar code in other language would _not_ work, and
without optimizations in current Haskell compiler
Maybe would significanly slow down programs

This is similar to fact that many Spad codes depend on
parametrized types, without such types code can not
be translated in simple way.

--
Waldek Hebisch

Qian Yun

unread,
Feb 24, 2021, 8:16:43 AM2/24/21
to fricas...@googlegroups.com


On 2/24/21 8:45 PM, Waldek Hebisch wrote:
> On Wed, Feb 24, 2021 at 06:12:45PM +0800, Qian Yun wrote:
>>
>>
>> On 2/24/21 2:00 AM, Waldek Hebisch wrote:
>>> On Tue, Feb 23, 2021 at 10:03:25AM +0800, Qian Yun wrote:
>>>>
>>>> I would like FriCAS to move away from "failed" and choose Haskell style
>>>> "Maybe" instead. This topic has been discussed before, I wonder if
>>>> Waldek's opinion has changed.
>>>
>>> Up to now I saw nothing to change my opinion. To clarify, automatic
>>> "lifting" of operations for T to say Maybe(T) would be useful.
>>
>> Why would that be useful? I think explicit type conversion is
>> better than implicit/automatic type conversion.
>
> It is really about automatically generating boilerplate code.
> If you do not want what Haskell offers and prefer to write
> code by hand, then I do not understand why you want Maybe.

I'm sorry, what boilerplate code are we talking about?
Do our current "failed" approach have boilerplate code?
We can perfectly use "Maybe" to replace "failed" with
almost zero boilerplate code. (Although there are
functional style to use "Maybe", instead of current
imperative style usage of "failed".)

>>> But up to now I do not see workable proposal how to implement
>>> such lifting and what exact rules should be. Without viable
>>> strategy for implementing extra functionality change to
>>> Maybe from my point of view looks pointless.
>>>
>>> To put is differenly, I view compiler, language and coding idioms
>>> as a whole. Clearly many language constructs need compiler
>>> support. Coding idioms depend on language and compiler.
>>> New coding idiom my be quite useful without new support.
>>> But IMO usefulness of Maybe depends very much on features
>>> of Haskell and Haskell compiler. While it may be
>>> possible to have useful effect is quite different way,
>>> mere change of notation does not look useful.
>>>
>>
>> I think in Haskell, "Maybe" is purely implemented as library
>> and requires zero compiler support.
>
> I admit that my understandin of Maybe is rather shallow,
> so please correct me if I am wrong. However I think:
> - Maybe is implementd by library
> - Maybe depends on language/compiler support is sense that
> similar code in other language would _not_ work, and
> without optimizations in current Haskell compiler
> Maybe would significanly slow down programs

I'm almost sure that "Maybe" doesn't need special Haskell
compiler treatment, a user implemented "Maybe" can achieve
similar performance. Because "Maybe" is such a simple
structure, the compiler can optimize it right away, no
need to special treat it at all.

On the other hand, in FriCAS compiler, "failed" is everywhere.
So I believe using "Maybe" to replace "failed" would be an
improvement, not only aesthetically, but also practically.

- Qian

Ralf Hemmecke

unread,
Feb 24, 2021, 8:48:10 AM2/24/21
to fricas...@googlegroups.com
> I'm almost sure that "Maybe" doesn't need special Haskell
> compiler treatment, a user implemented "Maybe" can achieve
> similar performance.  Because "Maybe" is such a simple
> structure, the compiler can optimize it right away, no
> need to special treat it at all.

Apart from such optimizations... why do you want Maybe instead of Partial?

(in axllib)
https://github.com/pippijn/aldor/blob/master/aldor/lib/axllib/src/al/partial.as

(or a bit more extended in the libaldor)
https://github.com/pippijn/aldor/blob/master/aldor/lib/aldor/src/base/sal_partial.as

Wouldn't that just be a question of naming?

I somehow would like failed?(x) better than isNothing(x) or isJust(x).

Anyway, I also like Partial/Maybe better than Union(X,"failed").
The Union(X,"failed") stuff is quite common in the FriCAS algebra
library. It doesn't mean that one must replace Union(X, "error1",
"error2") where two error cases are considered. But introducing
Partial/Mabe could produce more readable code and would certainly make
translating SPAD code to Aldor easier.

Ralf

Qian Yun

unread,
Feb 24, 2021, 8:52:50 AM2/24/21
to fricas...@googlegroups.com


On 2/24/21 9:48 PM, Ralf Hemmecke wrote:
>> I'm almost sure that "Maybe" doesn't need special Haskell
>> compiler treatment, a user implemented "Maybe" can achieve
>> similar performance.  Because "Maybe" is such a simple
>> structure, the compiler can optimize it right away, no
>> need to special treat it at all.
>
> Apart from such optimizations... why do you want Maybe instead of Partial?

I'm not promoting "Maybe" over "Partial".

As you said bellow, I'm not discussing about naming right now,
but to let everyone agree to move away from "failed"
to "this functional style error handling".

Thanks for your interest in my proposal.

- Qian

Mark Clements

unread,
Feb 24, 2021, 4:56:42 PM2/24/21
to fricas...@googlegroups.com
To help make this more concrete, I did a quick implementation of a
Partial domain in Spad (attached).

As a toy example comparing Union("failed", ...) with Partial(...):

UFloat ==> Union(Float,"failed")
partialSqrt x == (x>=0.0 => sqrt x; "failed") :: UFloat
partialSqrt 4.0 -- ok
partialSqrt (-4.0) -- ok

partialSqrt2 x == (x>=0.0 => partial sqrt x; failed()$Partial(Float))
partialSqrt2 4.0 -- ok
partialSqrt2 (-4.0) -- ok

The Partial domain avoids the explicit union type, but the "failed"
keyword from the union is shorter.

For this example (*without generalising*), the H-M type inference from
SML/Ocaml/Haskell is more elegant:

SML: fun partialSqrt x = if x>=0.0 then SOME (Math.sqrt x) else NONE;

Kindly, Mark.

On 24/02/2021 14:52, Qian Yun wrote:
>
>
> On 2/24/21 9:48 PM, Ralf Hemmecke wrote:
>>> I'm almost sure that "Maybe" doesn't need special Haskell
>>> compiler treatment, a user implemented "Maybe" can achieve
>>> similar performance. Because "Maybe" is such a simple
>>> structure, the compiler can optimize it right away, no
>>> need to special treat it at all.
>>
>> Apart from such optimizations... why do you want Maybe instead of
>> Partial?
>
> I'm not promoting "Maybe" over "Partial".
>
> As you said bellow, I'm not discussing about naming right now,
> but to let everyone agree to move away from "failed"
> to "this functional style error handling".
>
> Thanks for your interest in my proposal.
>
> - Qian
>
>> (in axllib)
>> https://eur01.safelinks.protection.outlook.com/?url=https%3A%2F%2Fgithub.com%2Fpippijn%2Faldor%2Fblob%2Fmaster%2Faldor%2Flib%2Faxllib%2Fsrc%2Fal%2Fpartial.as&amp;data=04%7C01%7Cmark.clements%40ki.se%7C7feb4780472b4e54e1d408d8d8cb79cb%7Cbff7eef1cf4b4f32be3da1dda043c05d%7C0%7C0%7C637497715729347066%7CUnknown%7CTWFpbGZsb3d8eyJWIjoiMC4wLjAwMDAiLCJQIjoiV2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3D%7C1000&amp;sdata=Aih8fRhdM8k%2FJvUIGvVA9UX1qNIW%2FzOC7FN0%2BRDn%2BjM%3D&amp;reserved=0
>>
>>
>> (or a bit more extended in the libaldor)
>> https://eur01.safelinks.protection.outlook.com/?url=https%3A%2F%2Fgithub.com%2Fpippijn%2Faldor%2Fblob%2Fmaster%2Faldor%2Flib%2Faldor%2Fsrc%2Fbase%2Fsal_partial.as&amp;data=04%7C01%7Cmark.clements%40ki.se%7C7feb4780472b4e54e1d408d8d8cb79cb%7Cbff7eef1cf4b4f32be3da1dda043c05d%7C0%7C0%7C637497715729347066%7CUnknown%7CTWFpbGZsb3d8eyJWIjoiMC4wLjAwMDAiLCJQIjoiV2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3D%7C1000&amp;sdata=nWRpGnvFomePzwwwPJh4OMsNgoH7iMMpXh9KsyvqQKk%3D&amp;reserved=0
>>
>>
>> Wouldn't that just be a question of naming?
>>
>> I somehow would like failed?(x) better than isNothing(x) or isJust(x).
>>
>> Anyway, I also like Partial/Maybe better than Union(X,"failed").
>> The Union(X,"failed") stuff is quite common in the FriCAS algebra
>> library. It doesn't mean that one must replace Union(X, "error1",
>> "error2") where two error cases are considered. But introducing
>> Partial/Mabe could produce more readable code and would certainly make
>> translating SPAD code to Aldor easier.
>>
>> Ralf
>>
>


När du skickar e-post till Karolinska Institutet (KI) innebär detta att KI kommer att behandla dina personuppgifter. Här finns information om hur KI behandlar personuppgifter<https://ki.se/medarbetare/integritetsskyddspolicy>.


Sending email to Karolinska Institutet (KI) will result in KI processing your personal data. You can read more about KI’s processing of personal data here<https://ki.se/en/staff/data-protection-policy>.
partial.spad

Qian Yun

unread,
Mar 1, 2021, 10:40:38 PM3/1/21
to fricas...@googlegroups.com
I guess we will have this conversion again a few years later then.

- Qian

Qian Yun

unread,
Mar 12, 2021, 2:36:40 AM3/12/21
to fricas...@googlegroups.com
I finally understand what Waldek called as "compiler support"
after reading some of the discussion a few years back.

On 10/16/16 6:40 AM, Waldek Hebisch wrote:
> Also, Spad compiler knows about unions, so we can use
> code like:
>
> ru := retractIfCan(x)@Union(T, "failed")
> ru case "failed" => "failed"
> r := ru::T
>
> and Spad compiler knows that coercion in third line is legit,
> because we excluded the other possibility in line 2. With
> 'Maybe' compiler will no longer accept code like above. Of course
> you may add explicit functions to test for failure and explicit
> function for coercion which calls error if value is not T, but
> then you loose static checking: once you add such coercion you
> can call it without performing check before.


BUT! Current Spad compiler does not have such special checks,
as this example shows, is this a bug?

--------------
)abbrev package TEST Test

Test() : Exp == Imp where
Exp == with
exquo2 : (Integer, Integer) -> Union(Integer, "failed")
Imp == add
exquo2(x, y) ==
a := x exquo y
t : Integer := a::Integer -- NO COMPILER ERROR HERE!
t
---------------

I understand that Waldek want to avoid "coercion which calls error if
value is not T", aka "fromJust : Maybe a -> a" which is a not total
function, it passes compiler check but may give runtime error.

Let me present how Haskell solves this problem:

From my limited Haskell experience, there are 3 ways:

1. Pattern matching. Effectively equals to
map : (Maybe A, A -> A) -> Maybe A
That is, deals with both the branch of "failed" and branch with type A.

2. Monad style >>=.
That is, use '>>=' on a series of functions with signature 'A -> Maybe A',
use '>>= : (Maybe A, A -> Maybe A) : Maybe A' to compose a series
of computation.

3. 'do' notation, which syntactic sugar over Monad.


I believe this "Maybe" style error handling is the right way to go.
Better abstraction, better model.

- Qian

Tobias Neumann

unread,
Apr 27, 2021, 1:50:45 PM4/27/21
to FriCAS - computer algebra system
> > The most problematic issue for me right now is that using ")compile
> > file.spad" multiple times
> > without ")clear all" in-between will completely break things. For example
> > something like:
> >
> > )co mypackage
> > test := sqrt(x)
> > subst(test, x=0)
> >
> > gives sqrt(0) as it should, but once I use )co mypackage again
> > it no longer substitutes x=0 and just returns sqrt(x). This then
> > completely breaks the functionality in the package.
> > A fix for this is to use ")clear all" in between, or to redefine test. Is
> > this "intended" or known behavior? I've had
> > similar issues before where ")clear completely" was necessary.

The issue was known, it has almost nothing to do with Spad compiler,
in particular the same should happen when using Aldor from FriCAS.
The core problem is that kernels are supposed to be unique.
Compilation has to invalidate existing domains, to make sure
that new code is used in all places. Kernels are stored in
separate domain called 'SortedCache', invalidating this domain
led to duplicate kernels and chaos. More precisely, there is
support for (at least somewhat) safely invalidating old kernels,
but it was not used. AFAICS attached patch solves your problem.

Your patch indeed fixed that example. But I came across a related issue, so it doesn't seem to be completely fixed.
I was able to produce a somewhat minimal bug example that can be enabled when recompiling a package.

I also came across an issue like that just when re-loading a matrix from a Library file, but I wasn't able to nail
it down to a minimal example yet. Hopefully it's the same underlying issue.

When enablebug is true, then the subtitution no longer works after recompiling any module. Strangely,
when enablebug is false, so I don't get tower for the matrix anymore, the issue doesn't appear.

----- SNIP -----
)clear completely

EI ==> Expression(Integer)

enablebug : Boolean := true
    
matrixKernels(x) ==
    removeDuplicates(reduce(append, map(tower, listOfLists(x))))


)co ptest.spad

if enablebug then
    mymat : Matrix(Expression(Integer))
    mymat := [[sqrt('x1)]]
    eval(matrixKernels(mymat)(1) :: EI, ['x1=4]) -- this is a crucial statement to cause the bug

myexpr : Expression(Integer)
myexpr := sqrt('x1)

eval(tower(myexpr)(1) :: EI, ['x1=4])

)co ptest.spad

if enablebug then
    eval(matrixKernels(mymat)(1) :: EI, ['x1=4])

eval(tower(myexpr)(1) :: EI, ['x1=4])

Ralf Hemmecke

unread,
Apr 27, 2021, 4:45:23 PM4/27/21
to fricas-devel
Without looking deeper into your snippet... is there a good reason that
you must first run some stuff in the session, then compile something and
later continue with your session?

Why can't you do all the compilation first and then run your computations?

Ralf

Waldek Hebisch

unread,
Apr 27, 2021, 8:25:51 PM4/27/21
to fricas...@googlegroups.com
I do not know what Tobias is doing, but rather typical developement
cycle is as follows:
1) compile your code
2) run some tests at command line
3) edit code to hopefully fix bugs
4) goto 1

To speed up this process it is convenient to preserve as much
of testing context as possible, that is reuse test expressions
stored in variables etc. There are workarounds, like storing
tests in input files, but in general bugs like this one
are problematic. Namely, when debugging freshly written code
bugs in libraries or interpeter are very undesirable, us
one would like to concentrate at current task and rely
on correct working of other FriCAS parts.

--
Waldek Hebisch

Tobias Neumann

unread,
May 3, 2021, 12:00:15 AM5/3/21
to fricas...@googlegroups.com
Quoting Waldek Hebisch (2021-04-27 20:25:42)
Yes, that is precisely my workflow and the reason I wanted to at least
report this bug. In my case some preprocessing of data takes quite a
while, and I want to quickly compile/edit/recompile and work with that
preprocessed data. While doing that I came across this issue, which
could in principle be avoided by saving the preprocessed data in a
Library for faster access. Similar issues happen there, but I haven't
been able to get a minimal example for that yet.

Best wishes,
Tobias
Reply all
Reply to author
Forward
0 new messages