1. For the program
---------------------------------------------------- t.spad ---------
DomConstr ==> Union(Symbol, FrConstr, UPConstr)
)abbrev domain FRCONS FrConstr
FrConstr(d : DomConstr) : DomConstr with frConstrArg : () -> DomConstr
== add
frConstrArg() == d
---------------------------------------------------------------------
(where DomConstr is erroneously set instead of SetCategory before `with')
the FriCAS-1.1.6 compiler reports
...
initializing NRLIB FRCONS for FrConstr
compiling into NRLIB FRCONS
>> System error:
The index 2 is too large.
The message does not look helpful for an user.
2. I have a beginner question about a user data type
----------------------------------------------------
I need to define a type DomConstr for the domain construction
descriptions, for a fixed small listed set of standard domain
constructors -- so far, let them be
Integer, Fraction, UP.
For example,
UP'(x, Fr(Int')) : DomConstr
expresses the construction of the domain UP(x, Fraction INT),
where UP', Fr', Int' are the type constructors which yield a domain
construction from other domain constructions and parameters.
Each tag (UP', POLY', Fr, ResidueRingConstr ...) has its particular
argument tuple of the parameters and constructions.
In Haskell, I define this type recursively, and as a disjoint union:
data DomConstr = Basic Symbol | Fr DomConstr | UP' Symbol DomConstr
And the above example of UP'(x, Fr(Int')) : DomConstr expresses as
(UP' x (Fr (Basic Int'))) :: DomConstr
Here Basic, UP', Fr are explicit user data tags.
The user program can build such data in this way, and also analyze them.
Example 1:
f constr = case constr of (UP' _ dom) -> dom
(Fr dom) -> dom
extracts from cons the coefficient domain construction -- if UP' is
at the top, and extracts the argument domain construction -- if Fr is at
the top.
Example 2: extractVariable constr = case constr of (UP' x _) -> Just x
_ -> Nothing
What is an adequate type (domain) description in Spad ?
I am trying
--------------------------------------------------------
category WithConstrSymbol ... Join SetCategory with
constrSymbol : () -> Symbol
-- the syntax needs correction
DomConstr ==> Union(Symbol, FrConstr, UPConstr)
-- instead of disjoint union?
)abbrev domain FRCONS FrConstr
FrConstr(d : DomConstr) : WithConstrSymbol with
frConstrArg : () -> DomConstr
== add
constrSymbol() == "Fr" :: Symbol
frConstrArg() == d
)abbrev domain UPCONS UPConstr
UPConstr(x : Symbol, d : DomConstr) : WithConstrSymbol with
upConstrVar : () -> Symbol
upCoefConstr : () -> DomConstr
== add
constrSymbol() == "UP'" :: Symbol
upConstrVar() == x
upCoefConstr() == d
--------------------------------------------------------
And I am going to build constructions like this:
constr := UPConstr(x, FrCons("Int" :: Symbol))
And to analyse it like this
f(constr) ==
constr case of Fr =>
constr' := frConstrArg constr
process the argument construction constr'
constr case of UP' =>
x := upConstrVar constr
cConstr := upConstrCoef constr
process x and the coefficient domain construction cConstr
This approach looks rather complex, and even requires to introduce a
category.
I thought of SExpression. But, for example,
convert[UP', x, coefConstr'] :: SExpressin
requires of UP', x, constr' to be of the same type. Right?
One neds to union the constructor tags, parameters (like x),
and domain constructions into a certain type U, and to program
processing the data in List U ...
Please, what may be an adequate way?
Thank you in advance for advice,
------
Sergei
mec...@botik.ru
> I thought of SExpression. But, for example,
> convert[UP', x, coefConstr'] :: SExpressin
> [..]
Now, I try Record:
-----------------------------------------------------------------------
DomConstr ==> Record(dConsName : Symbol, dConsDoms : List DomConstr,
dConsParams : DomConsParams)
-- Domain construction.
-- Examples:
-- Integer -- [INT::Symbol, [], "failed"],
-- Fraction INT -- [Fr, [INT], "failed"],
-- UP(x, Fraction INT) -- [UP, [Fr, [INT], "failed"], [x] ]
DomConsParams ==> Union("failed", List Symbol)
-- will be extended for other cosntructors
-----------------------------------------------------------------------
This is not so precise as `data' in Haskell, because some parts in this
record are not used by some constructors, and the length of the argument
and parameter lists is not restricted according to the constructor.
But I hope, it will work.
I do not know whether there exists a better solution.
Regards,
------
Sergei
mec...@botik.ru
On 03/03/2012 10:32 AM, Serge D. Mechveliani wrote:
> And I am going to build constructions like this:
>
> constr := UPConstr(x, FrCons("Int" :: Symbol))
>
> And to analyse it like this
>
> f(constr) ==
> constr case of Fr =>
> constr' := frConstrArg constr
> process the argument construction constr'
> constr case of UP' =>
> x := upConstrVar constr
> cConstr := upConstrCoef constr
> process x and the coefficient domain construction cConstr
>
> This approach looks rather complex, and even requires to introduce a
> category.
> I thought of SExpression. But, for example,
> convert[UP', x, coefConstr'] :: SExpressin
>
> requires of UP', x, constr' to be of the same type. Right?
> One neds to union the constructor tags, parameters (like x),
> and domain constructions into a certain type U, and to program
> processing the data in List U ...
Can you be a bit more precise? All I see is some code that looks like
Haskell and would certainly not be the way it would be programmed in
SPAD. It would be helpful, if you state, what you actually want to
achieve. From what I've read in your mail, all I can say is that you
want something like Any, but not encoding every type. In other words, I
think that you want tagged unions, but I'm not quite sure.
However, if you want something like Any or tagged union, then it looks
like you basically want to throw away the type information. I'm sure
there is some better way to achieve your goal in SPAD, but what is your
goal?
Ralf
The question can be reformulated: what Spad has for the tagged union?.
The initial goal is explained in the first my letter on this subject.
I repeat:
to define a type DomConstr
for an explicit symbolic representation of a domain construction
-- for a domain built by any correct composition of
INT, Fraction, UP, POLY, ResidueRingOfEuclideanRing.
(let it be this small set, so far)
-- each of these constructors has its individual tuple of argument types.
It must be so that a Spad program
could process constr : DomConstr as a first-class data, in particular,
to extract each part of constr : DomConstr.
For example, if constr : DomConstr represents the domain
UP(x, Fraction INT),
then, it is possible to extract from it the
tag "UP", variable x, (construction of Fraction INT) : DomConstr,
tag "Fraction", (construction of INT) : DomConstr.
I do not think that this needs `Any'.
In Haskell, it is done by a tagged union.
In Spad, I do not find tagged union.
(1) I tried to define domains and type union, as in my first letter.
(2) I thought of SExpression.
(3) In my second letter I applied Records.
Records do work for this goal, but they do not so precisely fit this goal.
For example, is it possible to define DomConstr as a
tagged union of several records?
Thanks,
------
Sergei
mec...@botik.ru
Tagged union in SPAD is something like
Union(i: Integer, f: Fraction Integer, ...)
but I bet, that is not what you want, since it is not equivalent to Haskell.
> The initial goal is explained in the first my letter on this subject.
Yes, I understood that part. But you haven't expressed the WHY.
Why would you want to put everything into one big type?
The reason for this question is that in my opinion that goes against the
typed way that one ought to program in SPAD. There must be a better
design. Perhaps you don't need such a DomConstr. So to ask it
differently: What do you want to achieve with your DomConstr? What
cannot be done if do don't have it? Why isn't it enough to have separate
types for INT, FRAC(INT), UP(x,...)?
> It must be so that a Spad program
> could process constr : DomConstr as a first-class data, in particular,
> to extract each part of constr : DomConstr.
That sounds a bit like you want some kind of expression domain (like
SExpression). However that would throw away the actual FriCAS types like
INT, FRAC etc. so I guess, you need something else.
> For example, if constr : DomConstr represents the domain
> UP(x, Fraction INT),
> then, it is possible to extract from it the
> tag "UP", variable x, (construction of Fraction INT) : DomConstr,
> tag "Fraction", (construction of INT) : DomConstr.
I can only guess, but maybe your wish has to do with selecting the right
function depending on the type of the object at hand???
Ralf
Please, where it is described how to use it?
> but I bet, that is not what you want, since it is not equivalent to Haskell.
>
>> The initial goal is explained in the first my letter on this subject.
>
> Yes, I understood that part. But you haven't expressed the WHY.
> Why would you want to put everything into one big type?
I am trying to compose a Spad function parseCall which parses from a
String a function call, for a certain restricted set of functions,
with parsing domain descriptions and the corresponding argument
descriptions, and a package call description -- given all in one String.
I am going to provide a working program for parseCall and then, to ask
whether it is reasonably done.
But I met an obstacle: I do not know how to define a
_recursive tagged type_.
Example
-------
a Tree over a type T is either a Leaf or
a Node containing v: T, left branch Tree, and right branch Tree.
In Haskell, this can be defined by intruducing a user type constructor
Tree and its type:
data Tree a = Leaf a | Node a (Tree a) (Tree a)
For example,
(Node 1 (Node 11 (Leaf 111) (Node 112 (Leaf 1121) (Leaf 1122)))
(Leaf 12)
)
-- :: Tree Integer
represents the tree 1
/ \
11 12
/ \
111 112
/ \
1121 1122
Example: the function f sums the numbers in all the tree:
f :: Tree -> Integer
f tree = case tree of Leaf n -> n
Node n left right -> n + (f left) + (f right)
What is the most appropiate approach in Spad to definig Tree(T) ?
I try Tree INT :
---------------------------------------------
INT ==> Integer
Tree ==> Union(Integer, Node)
)abbrev package FOO Foo
Foo() : with tree1 : INT -> Tree
== add
Node : Type :=
Record(nodeVal : INT, nodeLeft : Tree, nodeRight : Tree)
tree1(n : INT) : Tree == n :: Tree
---------------------------------------------
-- and tree1(2) does not work.
Thank you for advices,
------
Sergei
mec...@botik.ru
Correction:
> Please, where it is described how to use it?
Maybe in the source code?
https://github.com/hemmecke/fricas-svn/blob/master/src/algebra/complet.spad.pamphlet#L46
https://github.com/hemmecke/fricas-svn/blob/master/src/algebra/complet.spad.pamphlet#L60
Aldor User Guide?
http://www.aldor.org/docs/HTML/chap13.html#8
http://www.aldor.org/wiki/index.php/User_Guides_for_Compiler_and_Libraries
Ralf
OK, so you want a function:
parseCall: String -> String
that takes a string parses it, calls the respective FriCAS function and
returns the result as a string?
> But I met an obstacle: I do not know how to define a
> _recursive tagged type_.
Is this a second question? Maybe you don't need that for the above function.
In fact, up to my knowledge you cannot have the tagged equivalent of a
Haskell type definition.
I've once started aldor-combinat that allows to define recursive types
by higher order operators, but I have the impression that would be too
much overhead for your purpose.
Look, for parseCall, you handle all the things inside parseCall, and
there why would you need other types (INT, Fraction, SUP) as the ones
that are already provided by FriCAS. I don't get that point.
Maybe I don't understand that correctly, but you have to parse the type
information of your string and form a (true) FriCAS type X out of that.
Then with the help of this type X you interpret the actual expression in
order to form an element of X.
Of course, if your expression is composed from subexpressions, you have
to do all that recursively. But I somehow don't see why one would have
to introduce a Union type like your proposed DomConstr.
Ralf
Does this help?
https://github.com/hemmecke/fricas-svn/blob/master/src/algebra/tree.spad.pamphlet#L28
Ralf
I try to follow this, only to have a simpler example.
Define a
binary tree with INT in its nodes:
-------------------------------------------------------
INT ==> Integer
)abbrev domain BTREE BTree
BTree() : Export == Implementation where
Export == SetCategory with
tree : INT -> %
sumTree : % -> INT
Implementation == add
Node := Record(val : INT, left : %, right : %)
Rep := Union(leaf : INT, node : Node)
tree(n : INT) : % == [n] :: Rep
sumTree tr ==
tr case leaf => tr.leaf
tr case node =>
nd := tr.node
nd.val + sumTree(nd.left) + sumTree(nd.right)
--------------------------------------------------
-> tree 0
Internal Error
The function coerce with signature hashcode is missing from domain
BTree
Please, how to correct this?
How to change the implementation tree(n)
so that it would build, for example,
n
/ \
n+1 n-1
:: BTree
?
Thanks,
------
Sergei
mec...@botik.ru
That perhaps...
https://svn.origo.ethz.ch/algebraist/trunk/aldor/lib/axllib/test/tree.as
Well, you'd have to remove semicola and braces, of course and add the
)abbrev line, but it looks pretty much like what you want.
A leaf ther is something of the form [nodevalue, [], []], i.e. a value
together with two empty (binary) trees.
Ralf
tree.as : I fear dealing with Aldor + Spad will be even more difficult.
for me.
But here what seems now to work:
-- Binary tree over Integer -------------------------------------------
OF ==> OutputForm
INT ==> Integer
Node ==> Record(val : INT, left : %, right : %)
)abbrev domain BTREE BTree
BTree() : Export == Implementation where
Export == SetCategory with
coerce : % -> OF
empty : () -> %
tree : (INT, %, %) -> %
tree1 : INT -> %
sumTree : % -> INT
Implementation == add
Rep := Union(empty : "empty", node : Node)
coerce(t) : OutputForm ==
t case empty => "empty" :: OF
nd := t.node
l := coerce nd.left
r := coerce nd.right
hconcat["(", nd.val :: OF, ", ", l, ", ", r, ")"]
empty() == ["empty"]
tree(n, l, r) == [[n, l, r]]
sumTree tr ==
tr case empty => 0
tr case node =>
nd := tr.node
nd.val + sumTree(nd.left) + sumTree(nd.right)
tree1(n) == -- make example tree
tree( n, tree(n+1, empty(), empty()),
tree(n-1, empty(), empty()) )
-----------------------------------------------------------------------
1. I wonder why ["empty"] is needed instead of "empty"
(I mimiked this stupidly fron src/algebra/tree.spad*).
Similarly is tree(n, l, r) == [[n, l, r]],
-- as if additional [] coerces it to Rep.
2. Initially there was no "coerce(t) == "
The interpreter reported that coerce is missed from BTree.
What kind of coerce ?
Finally I guessed that it computes tree1(1), but cannot output.
So, probably, coerce(t) : OutputForm == ... is needed.
3. A recursive Record + Union cannot at all express the needed
recursive Tree type.
To define this recursive type it is needed
`domain' + Record + Union, and to use % inside Record !
And all this -- for expressing of what is expressed in a single line
in Haskell.
All right, at least it works!
Thank you for help,
------
Sergei
mec...@botik.ru
> tree.as : I fear dealing with Aldor + Spad will be even more difficult.
> for me.
I did not suggest to *use* aldor. But rather to take the code as an example.
Your code looked like having a bit of overhead. I cheated a bit with the
empty tree, by going back to LISP (see attachment). Well, if Record
exported a nil value for an empty record, that wouldn't have been
necessary. But Record doesn't (yet).
> And all this -- for expressing of what is expressed in a single line
> in Haskell.
Well, OK a lot of boilerplate in SPAD, but remember SPAD is not
functional and a rather different kind of language than Haskell.
Hope, by now you see the pattern.
Ralf
(1) -> B := BinaryTree(Integer)
(1) BinaryTree(Integer)
Type: Type
(2) -> empty()$B
(2) ()
Type: BinaryTree(Integer)
(4) -> t==>tree$B
Type: Void
(6) -> b := t(5, t 4, t 6)
(6) (5 (4 () ()) (6 () ()))
Type: BinaryTree(Integer)
(7) -> # b
(7) 3
Type: PositiveInteger
(8) -> sumTree b
(8) 15
Type: PositiveInteger
Then you should also wonder why two brackets are needed in [[n, l, r]].
The answer is clear from:
(1) -> )show Union(empty : "empty", node : Record(val:INT, left:%, right:%))
Union(empty: empty,node: Record(val: Integer,left: NIL,right: NIL))
is a domain constructor.
------------------------------- Operations --------------------------------
?=? : (%,%) -> Boolean ?case? : (%,empty) -> Boolean
?case? : (%,node) -> Boolean coerce : % -> OutputForm
construct : empty -> % ?.? : (%,empty) -> empty
?~=? : (%,%) -> Boolean
construct : Record(val: Integer,left: NIL,right: NIL) -> %
?.? : (%,node) -> Record(val: Integer,left: NIL,right: NIL)
where NIL is shown read %.
The notation [ ... ] is translated as a call to 'construct'.
But your confusion is understandable since the exports of tagged Union
in Axiom are very poorly designed.
Regards,
Bill Page.
Thank you.
And this )show may be helpful.
> that takes a string parses it, calls the respective FriCAS function and
> returns the result as a string?
1) I separate the two stages. parseCall prepares everything for applying
the needed standard function who's name is parsed at the top.
The remaining stage is simpler.
2) First, a string is broken to lexemes : LexList ==> List String.
I am going to try the format
------------------------------------------------------------
LexList ==> List String
PackageDescr ==> Product(Lexeme, Type)
ParseCallRes ==> Record(callName : Lexeme,
callDomConstrs : List DomainConstruction,
callDoms : List Type,
callArgs : List Any,
callPack : PackageDescr,
callRemLexs : LexList)
...
parseCall(lexemes : LexList) : ParseCallRes == ...
-- <call> ::= ( <fName> <domInputs> <argInputs> <packageInput> )
------------------------------------------------------------
The result is something ready to apply the specified Spad function to
the specified arguments, including their domains and including
possible package name and parameter values for the package.
There is chosen for this a finite set of the standard functions f =
"factor", "gcd", ... -- may be, 20-40 of them.
One of them will be applied after parsing.
Each of them has a fixed signature, but the call includes the
specification for each argument domain. Each of these domains has a
construction composed of INT, Fraction, UP, POLY, ResidueRing
-- several of them. It can be exxtende, bu it is fixed for each month.
<domInputs> is the input for such domain.
parseCall parses a symbolic domain construction, and also the very
domain. These data are used further in parsing the arguments of the
call.
There are possible variants.
> Look, for parseCall, you handle all the things inside parseCall, and
> there why would you need other types (INT, Fraction, SUP) as the ones
> that are already provided by FriCAS. I don't get that point.
I also do not understand you.
For example, 'factor' can be applied to f : UP(x, D),
where D can be constructed by an arbitrary many compositions of
various domain constructors. D may be Z = INT, Fraction Z,
(Fraction Z)[y]/(y^2 - 2) -- a residue ring,
and so on.
All this must be parsed from zero, from lexemes.
parseCall needs to find all this from
<call> ::= lexemes :=
"(" <fName> <domInputs> <argInputs> <packageInput> ")"
First to parse from lexemes : what is this D.
After D is found, the parser can parse the lexemes for f, with
taking each _coefficient input_ to a correct domain D.
For example, to parse a fraction coefficient from ["(" "Fr" <a> <b> ")"],
one needs to apply (a/b) :: Fraction D', where D' is correctly found,
and a, b : D' are parsed from <a>, <b>.
Neither the needed domains nor the coefficients are known initially,
only lexemes : LexList are given.
Besides `factor' there are possible several other functions, very
polymorphic ones.
> Of course, if your expression is composed from subexpressions, you have
> to do all that recursively. But I somehow don't see why one would have
> to introduce a Union type like your proposed DomConstr.
Because there is a fixed finite set of the standard domain constructors
of whiwch a goal domain is built. So, a domain construction DomConstr is
a Tree which edges are these constructors. This is expressed as
`domain' + tagged union + % (recursion)
-- as you have kindly explained.
What is wrong here?
Regards,
------
Sergei
mec...@botik.ru
Sergei,
1) You give ParseCallRes as a return type. But isn't it true that in the
end you want to have a string that you can send back to Haskell?
2) Can you upload your code to your account on github and give me a link
to it. That would make it easier for me to see the development of your
code and enable me to propose some changes directly to your code.
Ralf
Stage 2 will apply the needed f and produce a result r.
(1) pRes : ParseCallRes and r can be used in Axiom, independently of
Haskell. Because this is a fast special parsing
(I do not know now of how it can be used).
(2) r is printed to a string and sent back to Haskell
-- for the DoCon users.
> 2) Can you upload your code to your account on github and give me a link
> to it. That would make it easier for me to see the development of your
> code and enable me to propose some changes directly to your code.
http://botik.ru/pub/local/Mechveliani/axiQuest/DParse.zip
is the initial version. It works. See readme.txt.
In this version
1) a domain is parsed in the same process when an element in parsed,
2) it parses one element, it does not parse a whole call.
parseCall is the further and necessary generalization, I hope it
will also parse the elements in a better way.
In both programs `Any', `pretend', and may be, `retract' are necessary,
in parseCall `Any' will be more located, I hope.
I am only starting with parseCall. After it is done, I shall tell you.
Is
http://botik.ru/pub/local/Mechveliani/axiQuest/
all right?
Thanks,
------
Sergei
mec...@botik.ru
Yes, and this is what I don't like. Well, we may have different ideas of
how things should work, so if I don't like something that doesn't
necessarily mean that you do something wrong.
But the reason why I don't want r and especially its type is, because it
is unnecessary. All you need is a string format of the result. And that
you get by converting the result into OutputForm (or whatever).
OutputForm is just one type and that is good enough.
So my idea would be to parse the string, dive deeper while parsing, i.e.
building the intermediate types recursively and basically just return
OutputForm. But well, I don't know whether this would work.
Another idea would be the following. There is a rather big freedom of
what you send from Haskell to FriCAS. In recent mails you've already
included type information.
What about starting with just simple functions. I.e. from Haskell you
send (a more parse-friendly string) of
a1: T1 := v1; a2: T2 := v2; r: T := f(a1, a2)$P; r::OutputForm
v1 and v2 would be simple values like Integer, Float or String (nothing
complicated like polynomials).
In fact, you can send something like a well designed *.input file to
FriCAS and let the FriCAS parser do the hard work.
You said before that this is too slow. Is it already too slow to parse
and call a function in case T1=T2=T=Integer?
>> 2) Can you upload your code to your account on github and give me a link
>> to it. That would make it easier for me to see the development of your
>> code and enable me to propose some changes directly to your code.
>
> http://botik.ru/pub/local/Mechveliani/axiQuest/DParse.zip
Well, I really meant GitHub, because that would make it easier to
develop code and see differences.
> I am only starting with parseCall. After it is done, I shall tell you.
Well, the whole point is that you should not do it alone but rather in
public (and on github). I hope you are familiar with version control,
otherwise you might learn an appreciate it while we try to develop together.
> Is
> http://botik.ru/pub/local/Mechveliani/axiQuest/
> all right?
For the moment yes. It'll take me some time to delve into it and since I
am busy with other things, I'll probably not have a helpful comment on
the code before Sunday.
Ralf
http://botik.ru/pub/local/Mechveliani/axiQuest/DParse-0.02.zip
contains a fresh dParse -- for parsing element + domain.
See readme.txt and comments.
If you provide your code, then you can either give a link or just
send me an archive in an e-mail attachement.
Will this do?
> It'll take me some time to delve into it and since I
> am busy with other things, I'll probably not have a helpful comment on
> the code before Sunday.
I can wait. Meanwhile can do my attempts.
> Another idea would be the following. There is a rather big freedom of
> what you send from Haskell to FriCAS. In recent mails you've already
> included type information.
>
> What about starting with just simple functions. I.e. from Haskell you
> send (a more parse-friendly string) of
>
> a1: T1 := v1; a2: T2 := v2; r: T := f(a1, a2)$P; r::OutputForm
>
> v1 and v2 would be simple values like Integer, Float or String (nothing
> complicated like polynomials).
But how to input, for example, a polynomial
f : UP(x, INT), UP(x, Fraction INT) ?
> In fact, you can send something like a well designed *.input file to
> FriCAS and let the FriCAS parser do the hard work.
>
> You said before that this is too slow. Is it already too slow to parse
> and call a function in case T1=T2=T=Integer?
I thought of this. In dParse I control everything. And it is difficult
for me to control parse * interpet by FriCAS
(please, look into testParse.spad).
Eample:
In DParse-0.02, (4*x^3 + 5*x - 6) : UP(x, INT) is input as
"(UP x 1 [3 1 0] [4 5 -6])"
After "(", "UP", "x", it finds: f : UP(x, D), D to be found.
After "1", it finds that D = Integer.
Then "[3 1 0]" is parsed to the list of NonNegativeIntegers -- exponents,
"[4 5 -6]" is parsed to the List Integer -- coefficients.
Then the exponents and coefficients are zipped with the `monomial'
function, and the monomial list is coerced to f : UP(x, INT).
In the input, the exponents are already ordered as needed.
The whole algorithm is _linear_.
UP(x, Fraction INT) is similar, and so on.
Why do you think that
a1: T1 := v1; a2: T2 := v2; r: T := f(a1, a2)$P; r::OutputForm
is cheaper?
I suspect that in both programs computing domains takes a considerable
cost.
> and let the FriCAS parser do the hard work.
1) Look into dParse : String -> ... in DParse-0.02.
There is no hard work.
A hard work is studying Spad. For example, I define
Rep := Union(dConsBasic : Symbol, dConsFr : %, dConsUP : UPCons),
and now think: how to coerce "INT" :: Symbol to Rep, as dConsBasic ?
So far, I fail.
2) In " a1: T1 := v1; a2: T2 := v2; r: T := f(a1, a2)$P; r::OutputForm",
FriCAS will do parse * interpret.
I expect, dParse is 10 times faster. Also I need to find out whether it
can be done 50 times faster, some optimizations.
On Mon, Mar 05, 2012 at 09:23:26PM +0100, Ralf Hemmecke wrote:
>>> 1) You give ParseCallRes as a return type. But isn't it true that in the
>>> end you want to have a string that you can send back to Haskell?
>>
>> Stage 2 will apply the needed f and produce a result r.
>
> Yes, and this is what I don't like. Well, we may have different ideas of
> how things should work, so if I don't like something that doesn't
> necessarily mean that you do something wrong.
>
> But the reason why I don't want r and especially its type is, because it
> is unnecessary. All you need is a string format of the result. And that
> you get by converting the result into OutputForm (or whatever).
> OutputForm is just one type and that is good enough.
All right, imagine parseCall2 : LexList -> OutputForm, String.
If it is faster, then all right.
But I do not guess how this String may help.
String is almost the same as Any.
May be, you have some idea of which I do not guess.
> So my idea would be to parse the string, dive deeper while parsing, i.e.
> building the intermediate types recursively and basically just return
> OutputForm.
Among these intermediate types there will meet `Any', and `pretend' and
`retract' will be needed to apply a cople of times. I cannot imagine how
can this be avoided.
> But well, I don't know whether this would work.
As DParse-0.02 works in examples (with Any, retract, pretend, with
parsing a domain -- please see dParse), this parseCall has to work too.
After I started to believe that DParse-0.02 works, the problem remains in
the performance.
Regards,
------
Sergei
mec...@botik.ru
All you need is git and ssh. Pretty standard on any linux pc.
What other programs are you asked to install?
Use the standard packaging of you linux distribution.
sudo apt-get install gitk #<-- that's all for debian
http://help.github.com/linux-set-up-git/
You have to create an ssh key and upload the public key to github.
Finally you have to run
git config --global user.name "Firstname Lastname"
git config --global user.email "your_...@youremail.com"
Well, then you log into github and either go to
https://github.com/hemmecke/fricas-svn and click on the "Fork" button or
you click "New repository" directly on
https://github.com/YOURGITHUBNAME
> http://botik.ru/pub/local/Mechveliani/axiQuest/DParse-0.02.zip
> contains a fresh dParse -- for parsing element + domain.
Downloading and installing your new version is a little more work than
if I simply can call "git fetch" to get all the modifications. And for
you a "git push" would be simple enough to upload your latest version.
No need to "invent" a version number, since git produces enough metadata.
Ralf
> You have to create an ssh key and upload the public key to github.
It is difficult. It is written there config ...
Om my machines there is ~/.ssh/known_hosts ...
But on my home machine, there is no config.
On the machine at work, there is only /usr/bin/config_data,
I do not know what it is for.
Running it may break some vital connections.
I need to consult with Linux experts, and I fear, this will be after
March 11.
Thanks,
------
Sergei
mec...@botik.ru
Yes, for printed output you need this coercion.
--
Waldek Hebisch
heb...@math.uni.wroc.pl
You decided to do dispatching on types, but maybe alternative
design is better?. Namely you mix parsing expressions with
parsing types and apparantly you want to re-do parsing types
to choose correct function to apply. But you could have
mappings:
String -> Type
String -> parser function
String -> encoder function
(String, String, List(String)) -> application funnction
The fist one given a string would return FriCAS type T
(this is what you are doing in dParse). The second one
given a String would return parser, that is function from
strings (or list of lexemes) to T. The third one is
"inverse" of second one: will give you a function
which will encode values of type T into strings.
The fourth one given name of FriCAS function, encoded
return type and encoded argument types would return
apropriate function. Actually, you may also need
to know domain/package which implements given function,
that it you may need extra argument.
This may be more code that you intended to write (in
particular I do not see how to do this using a _single_
function), but may be less code compared to what you end
up writing. In particular the same parsing machinery
could be used for all four tasks. Also, such approach
should have better performance, namely in your approach
amount of dynamic dispatching is proportional to size of
data (for example you are re-doing dispatching for each
coefficient of a polynomial), while in what I propose
dispatching is proportional to size of types.
--
Waldek Hebisch
heb...@math.uni.wroc.pl
Waldek, I like that. It somehow reminds me of
https://svn.origo.ethz.ch/algebraist/trunk/aldor/lib/algebra/src/extree/sit_extree.as
But, in fact, in some sense your approach is more general.
Anyway, if Sergei is able to prepare the string that is sent to fricas,
one could prepend each item with the (FriCAS) type it should belong to
and *a parse function from this type* would then parse and read the next
item. And such parse functions could call parse funcions from other
types recursively.
For example. Assume I want to read a polynomial of type UP(x, FRAC INT).
The first thing would be to have a preparation phase where all the
involved types in the expression are listed and given a name. So we
would have
Z:=Integer
Q:=Fraction Z
P:=UnivariatePolynomial(x, F)
In fact that is somewhat similar to constructing these types in a online
session. And one can probably let the FriCAS interpreter do the parsing
for these types.
Then the actual polynomial (for example 3/4*x^3 + 7/5*x + 4/1) that
would be send from Haskell, would look like this
(P (P P P) + (P (Q Z) * (Q (Z Z) / 3 4) 3)
(P (Q Z) * (Q (Z Z) / 7 5) 1)
(P (Q Z) * (Q (Z Z) / 4 1) 0))
General pattern: (RET-TYPE (ARG-TYPES) FUNNAME actual-arguments)
Excuse me. I've simplified x^n a bit.
As Waldek mentioned, in some cases, it might not be enough to have
argument and return types given and one would have to find a way to
package call a certain function.
Does that sound reasonable?
Ralf
I thank Waldek and Ralf for thier advices.
1. I am in the middle of the attempt with parseCall, and need to finish
it. Then, I shall a) show the source and description,
b) ask for comments, c) think of your suggestion.
Most my time is spent not to the design, nor to real programming, but to
studying Spad. For example, to find a usage of tagged union has taken
of me about 12 hours of attempts, even with your help.
2. I knew that parsing a domain must, probably, be by constructing it
from a table of assignment inputs. Because domains may repeat and may
have large common parts.
3. Currenly, I keep in mind the input like the following.
Consider the call
UPol := UnivariatePolynomial(x, Fraction Integer)
gcd(3/4*x^3 +7/5*x +4, x^9 -2*x^4 -x^2 +1/3) $UnivariateGcd(UPol)
-- let gcd and UnivariateGcd be contrived, I do not know whether
such exist in Axiom and whether they are needed in reality.
It is sent to parseCall as
"( gcd -- head function name
[(F = Fraction INT) (P = UP x F)] -- table of type input
P -- returned type input
[P P] -- argument list input
(UnivariateGcd P) -- package call input
[ -- argument input list
(UP [3 1 0] [(Fr 1 1) (Fr 7 5) (Fr 4 1)]) -- arg1
(UP [9 4 2 0] [(Fr 1 1) (Fr -2 1) (Fr -1 1) (Fr 1 3)]) -- arg2
]
)"
Here <UP input> ::=
"(" "UP" <exponent list input> <coefficient list input> ")",
"UP" and "Fr" are not really necessary here in arg1, arg2,
as it is visible below.
After lexLots, parseCall deals with
["(", "gcd" ... "P", "UnivariateGcd" ... ] : LexList ==> List String
First, the types F and P are parsed from the table input.
Each type is parsed to
Product(Type, DomainConstruction)
Then, arg1 is parsed by
parseElem(P, PConstr,
lexLots "(UP [3 1 0] [(Fr 1 1) (Fr 7 5) (Fr 4 1)])"
),
where P : IntegralDomain = UP(x, Fraction INT),
PConstr : DomainConstruction = UP x (Fr INT)
-- a member of a certaing tagged union.
And so on.
4. The next generalization will be needed:
parsing ResidueRing(R, Ideal(f_1...f_n))
involves parsing the elements f_i of R.
5. After observing my parseCall, you can write you own improvement,
may be, designed totally by new.
If it occurs considerably faster, I hope to be able either to continue
it or to formulate what is neeeded to cover the DoCon needs.
I also need to do a) DoCon --> String for Axiom,
b) Axiom result --> String for DoCon,
c) fast parsing in DoCon (not done yet!).
All that I see now is that FriCAS has unnaturally slow parsing of
algebraic data, which makes the String interface almost useless.
Regards,
------
Sergei
mec...@botik.ru
Serge, again... read the Aldor User Guide! Even if it is not exactly
describing SPAD, But it is close enough to serve as a starter. And there
you will find out about everything. Usage you always find by either
grepping the aldor libraries
svn checkout https://svn.origo.ethz.ch/algebraist/trunk aldor
or the fricas sources (under src/algebra/). I have no idea how you were
able to waste 12 hours. That would really better have spent with
http://www.aldor.org/docs/aldorug.pdf.
Ralf
Sergei, did you see Fr in my mail? Didn't you get the point of assigning
"Z:=Integer;F:=Fraction(Z);..." and then using Z, F, etc in the string
that would have to be parsed, i.e. there is no generic denotation in
your argument strings (arg1, arg2), but this rather depends on what you
assign previously to the types, i.e. to Z, F etc.
The reason was that reparsing types is avoided, because all this is done
at the beginning and done just once.
Even more is true. If you connect to FriCAS and keep the connection
open. Then you probably just have to transfer the data once per session.
In other words, you basically talk from Haskell with the FriCAS interpreter.
Waldek, do you know whether the interpreter would still be slow if it
get's enough type information so that functions selection would be
unique and basically no need to search for the right option among
alternatives?
Sorry, but I haven't yet looked at the way Sergei connects Haskell with
FriCAS.
Ralf
In my letter it _was written_ that these repeated "Fr" and "UP" in
arg1, arg2 _are not necessary_.
Why do you skip this?
I have set these "Fr" for you to read this easier.
> Didn't you get the point of assigning
> "Z:=Integer;F:=Fraction(Z);..." and then using Z, F, etc in the string
> that would have to be parsed,
In my above format it is visible, that "P" is set in the input 4 times
instead of (UP (Fraction INT)).
I do not understand your first two questions.
> i.e. there is no generic denotation in
> your argument strings (arg1, arg2), but this rather depends on what you
> assign previously to the types, i.e. to Z, F etc.
More precisely, I meant this:
"( gcd -- head function name
[(F = Fr INT) (P = UP x F)] -- table of type input
P -- returned type input
[P P] -- argument list input
(UnivariateGcd P) -- package call input
[ -- argument input list
( [3 1 0] [(1 1) (7 5) (4 1)] ) -- arg1
( [9 4 2 0] [(1 1) (-2 1) (-1 1) (1 3)] ) -- arg2
]
)"
It is evident. Because after P is parsed,
_together with its construction_,
it is clear for parseCall that the first list in arg1
is for NNI-s for exponents and the second list is for List Fraction INT.
For example, "(1 1)" in arg1 will be parsed by applying a more special
parseFraction(INT, "INT", "(1 1)").
Because to this moment, parseCall allready expects a fraction over INT.
May be, I am missing something.
But I cannot do these three things in the same time:
1) composing/debugging a program,
2) explaining everything about this,
3) understanding other approaches to this program.
So far, I only asked "how to use named union?"
(and finally have got the answer).
I need 1) to finish this parseCall,
2) to write down its design description -- explanation,
3) to show the result.
And then, I shall try to understand your possible notes of what is wrong
there, and to discuss the alternatives.
Because I have a feeling (it may occur wrong) that mainly the intended
design is all right.
> The reason was that reparsing types is avoided, because all this is done
> at the beginning and done just once.
It is visible from my last two letters, that in my intended program the
types are _not reparsed_.
> Even more is true. If you connect to FriCAS and keep the connection
> open. Then you probably just have to transfer the data once per session.
>
> In other words, you basically talk from Haskell with the FriCAS interpreter.
>
I do not understand this.
I think, it is faster for DoCon to "talk" with
the compiled Spad function parseCall + applying this call +
read/write of Axiom for String and the two _named pipes_.
Regards,
------
Sergei
mec...@botik.ru
> Why do you skip this?
I apologize. But you would have less confused me if you hadn't written
the Fr in your expression at all.
Ralf
>> In other words, you basically talk from Haskell with the FriCAS interpreter.
>>
>
> I do not understand this.
> I think, it is faster for DoCon to "talk" with
>
> the compiled Spad function parseCall + applying this call +
> read/write of Axiom for String and the two _named pipes_.
Oh, maybe I don't yet understand your design. Or maybe I don't
understand FriCAS, but I wouldn't know how to talk to fricas other than
via the interpreter.
Basically you send a string (the whole following line including
"parseCall" and the quotation marks"
parseCall "IN THIS STRING THE EXPRESSION FROM YOUR LAST MAIL"
and parseCall would return a string.
I would send one or more lines to the interpreter. The first few lines
would assign the types
Z := ...
Q := ...
...
and the last line would be something like
foo "THE EXPRESSION GOES HERE"
where foo is something like your parseCall. But since at that point, you
already have the argument and target types constructed, one would better
call something like
foo(RETTYPE, ARGTYPE1, ..., ARGTYPEn, "EXPRESSION")
Well,... I stop here, I haven't made up my mind completely of how to do
the parsing. Give me more time.
Ralf
The Axiom interpreter evaluates the below loop of `repeat' :
------------------------------------------------ fifoFromA.input -------
toA : TextFile := open("toA", "input")
fromA : TextFile := open("fromA", "output")
repeat
iStr := readLineIfCan! toA
if iStr case "failed" then
(output ""; output "input -> failed"; break)
output "iStr = " iStr "\n"
strings := split(iStr, char ";") $String
strings' := map(parseEvalShow, strings) --
str := concat intersperse(";", strings')
resStr := concat[str, newline() :: String]
writeLine!(fromA, resStr)
flush(fromA)
------------------------------------------------------------------------
`repeat'
(1) inputs a string from the named pipe toA;
(2) splits to to several call inputs, each of type String;
(3) applies parseEvalShow str to each call input str.
(4) writes back to the pipe "fromA" the result strings strings'.
(several calls are transferred at a time, in order to possibly reduce
the number of calls for input/output with pipes).
Here parseEvalShow : String -> String
is programmed in Spad, compiled and loaded before running
fifoFromA.input.
The main Axiom part is in parseEvalShow:
parseCall, evaluate it by applying the head function,
output to String.
This all I mean by saying
"DoCon talks with the compiled Spad function parseEvalShow:
parseCall + applying this call + read/write of Axiom".
For example, for factoring -4x^3 +5x^2 +6 : UP(x, INT), it is input
"(factor [(P = UP x INT)] -- type input table
(UnivariateFactorize P) -- package call
[(Factorize P) P] -- signature of `factor'
[([3 2 0] [-4 5 6])] -- polynomial
)"
At the stage of `evaluate', it applies in this example
factor(<prasedPolynomial>) $UnivariateFactorize(<parsedDomain>)
And I hope that after
D := parseDomain(<needed input>) pretend SuchAndSuchRing
(which expresses the above P ) is computed, the call
factor(<prasedPolynomial>) $UnivariateFactorize( D )
will work.
Will it?
If it will, then this would mean `evaluate'.
and the first problem will be the performance of parseCall.
And the idea to replace the "parse - interpret" part of FriCAS with
my parseEvalShow.
Such is the situation.
Regards,
------
Sergei
mec...@botik.ru