On 13.04.23 16:18, Waldek Hebisch wrote:
> Of course, all needed redirections and buffering could be hidden in
> an utility function. AFAICS need to run external programs and
> capture output is rare enough that nobody bothered to write a
> special function.
I have written a simple stupid interface that can call any external program.
I can call Sage via
)compile runextcmd.spad
RUN ==> run $ RunExternalCommand
out := RUN("/bin/sh sage.sh", "[x^2 for x in range(40)]")
or
setExecutable("sage", "/bin/sh sage.sh")
out := RUN("sage", "[x^2 for x in range(40)]")
This will give the value:
(5)
["[0,", " 1,", " 4,", " 9,", " 16,", " 25,", " 36,", " 49,", " 64,",
" 81,",
" 100,", " 121,", " 144,", " 169,", " 196,", " 225,", " 256,", "
289,",
" 324,", " 361,", " 400,", " 441,", " 484,", " 529,", " 576,", "
625,",
" 676,", " 729,", " 784,", " 841,", " 900,", " 961,", " 1024,", "
1089,",
" 1156,", " 1225,", " 1296,", " 1369,", " 1444,", " 1521]"]
Type: List(String)
Of course, that needs to be brought back into proper FriCAS objects like
str := concat out
(6)
"[0, 1, 4, 9, 16, 25, 36, 49, 64, 81, 100, 121, 144, 169, 196, 225,
256, 289,
324, 361, 400, 441, 484, 529, 576, 625, 676, 729, 784, 841, 900,
961, 1024,
1089, 1156, 1225, 1296, 1369, 1444, 1521]"
(7) -> inf := parse(str)$InputForm
(7)
(construct 0 1 4 9 16 25 36 49 64 81 100 121 144 169 196
225 256 289 324 361 400 441 484 529 576 625 676 729 784
841
900 961 1024 1089 1156 1225 1296 1369 1444 1521)
Type: InputForm
(8) -> interpret(inf)
(8)
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81, 100, 121, 144, 169, 196, 225,
256, 289,
324, 361, 400, 441, 484, 529, 576, 625, 676, 729, 784, 841, 900,
961, 1024,
1089, 1156, 1225, 1296, 1369, 1444, 1521]
Type: List(NonNegativeInteger)
sage.sh is:
==============================
#!/bin/sh
base=$(basename $1 .tmp)
cat $1 | sage -q | sed 's/^sage: //' > $base.out
==============================
The first parameter that script gets is a filename of the form
rxcXXXXX.tmp where the XXXXX is a random number (random(2^32)).
Clearly, this enables me not only to call Sage, but also Maple,
Mathematica, etc. The question is only whether I do the massaging of the
output of the respective programs (sage, mathematica, maple) in the
respective shell script or via string transformations in FriCAS. For
Sage I have chosen the script, because string handling in FriCAS is
rather limited without having an equivalent to regular expression
handling like in sed/awl/perl.
If I could eliminate the need of accessing the file system that would be
great. I guess, it should be diable if I use specific features from
SBCL, but I would like to have something that works for any lisp that
FriCAS supports.
> You do not say what you want from Sage. IMO "proper" way of using
> external programs involves appropriate communitation protocol and
> ways to translate data.
Proper way is more involved. What I want is just to give our users
something at hand that enables them to build on top of a simple
communication protocol (like my RunExternalCommand) and do the remaining
"interpret(parse make_output_fricas_like(external_output)" in an ad hoc
fashion.
This might or might not be the start of a true interface to external CAS
(not really my goal), but I just wanted to call two functions from Sage
and use their output for comparison/testing of my code.
> OTOH I am not sure if there are good ways to get information out of
> Sage.
In general, you are right. But I do not want to write an interface to
everything in Sage. That would be equally difficult as the interface to
FriCAS in Sage. It also only covers a part of FriCAS.
Recently, Kurt told me about his experiments.
https://github.com/nilqed/spadlib/blob/master/pipe/src/pipe.spad
I haven't yet experimented with it, but it looks interesting.
I might probably use that for myself, but this code seems to be bound to
SBCL and not easily doable if the underlying lisp can be any other of
the FriCAS supported lisps.
Ralf