/*, */, // | comments |
Prog, [, ] | block of statements |
Bodied, Infix, Postfix, Prefix | define function syntax |
IsBodied, IsInfix, IsPostfix, IsPrefix | check for function syntax |
OpPrecedence, OpLeftPrecedence, OpRightPrecedence | get operator precedence |
RightAssociative | declare associativity |
LeftPrecedence, RightPrecedence | set operator precedence |
RuleBase | define function with a fixed number of arguments |
RuleBaseListed | define function with variable number of arguments |
Rule | define a rewrite rule |
HoldArg | mark argument as not evaluated |
Retract | erase rules for a function |
UnFence | change local variable scope for a function |
HoldArgNr | specify argument as not evaluated |
RuleBaseArgList | obtain list of arguments |
MacroSet, MacroClear, MacroLocal, MacroRuleBase, MacroRuleBaseListed, MacroRule | define rules in functions |
Backquoting | macro expansion (LISP-style backquoting) |
SetExtraInfo, GetExtraInfo | annotate objects with additional information |
GarbageCollect | do garbage collection on unused memory |
FindFunction | find the library file where a function is defined |
Secure | guard the host OS |
/* comment */ // comment |
a+b; // get result a + /* add them */ b; |
Prog(statement1, statement2, ...) [ statement1; statement2; ... ] |
Prog(a,b); is the same as typing [a;b;]; and is very useful for writing out function bodies. The [ ... ] construct is a syntactically nicer version of the Prog call; it is converted into Prog(...) during the parsing stage.
Bodied("op", precedence) Infix("op") Infix("op", precedence) Postfix("op") Postfix("op", precedence) Prefix("op") Prefix("op", precedence) |
precedence -- nonnegative integer (evaluated)
In> YY x := x+1; CommandLine(1) : Error parsing expression In> Prefix("YY", 2) Out> True; In> YY x := x+1; Out> True; In> YY YY 2*3 Out> 12; In> Infix("##", 5) Out> True; In> a ## b ## c Out> a##b##c; |
IsBodied("op") IsInfix("op") IsPostfix("op") IsPrefix("op") |
In> IsInfix("+"); Out> True; In> IsBodied("While"); Out> True; In> IsBodied("Sin"); Out> False; In> IsPostfix("!"); Out> True; |
OpPrecedence("op") OpLeftPrecedence("op") OpRightPrecedence("op") |
For infix operators, right precedence can differ from left precedence. Bodied functions and prefix operators cannot have left precedence, while postfix operators cannot have right precedence; for these operators, there is only one value of precedence.
In> OpPrecedence("+") Out> 6; In> OpLeftPrecedence("!") Out> 0; |
RightAssociative("op") |
RightAssociative("*") |
LeftPrecedence("op",precedence) RightPrecedence("op",precedence) |
precedence -- nonnegative integer
This functionality was required in order to display expressions like a-(b-c) correctly. Thus, a+b+c is the same as a+(b+c), but a-(b-c) is not the same as a-b-c.
Note that the left and right precedence of an infix operator does not affect the way Yacas interprets expressions typed by the user. You cannot make Yacas parse a-b-c as a-(b-c) unless you declare the operator "-" to be right-associative.
RuleBase(name,params) |
params -- list of arguments to function
In the context of the transformation rule declaration facilities this is a useful function in that it allows the stating of argument names that can he used with HoldArg.
Functions can be overloaded: the same function can be defined with different number of arguments.
RuleBaseListed("name", params) |
params -- list of arguments to function
A function defined using RuleBaseListed will appear to have the arity equal to the number of parameters in the param list, and it can accept any number of arguments greater or equal than that. As a consequence, it will be impossible to define a new function with the same name and with a greater arity.
The function body will know that the function is passed more arguments than the length of the param list, because the last argument will then be a list. The rest then works like a RuleBase-defined function with a fixed number of arguments. Transformation rules can be defined for the new function as usual.
RuleBaseListed("f",{a,b,c}) 10 # f(_a,_b,{_c,_d}) <-- Echo({"four args",a,b,c,d}); 20 # f(_a,_b,c_IsList) <-- Echo({"more than four args",a,b,c}); 30 # f(_a,_b,_c) <-- Echo({"three args",a,b,c}); |
In> f(A) Out> f(A); In> f(A,B) Out> f(A,B); In> f(A,B,C) three args A B C Out> True; In> f(A,B,C,D) four args A B C D Out> True; In> f(A,B,C,D,E) more than four args A B {C,D,E} Out> True; In> f(A,B,C,D,E,E) more than four args A B {C,D,E,E} Out> True; |
The function f now appears to occupy all arities greater than 3:
In> RuleBase("f", {x,y,z,t}); CommandLine(1) : Rule base with this arity already defined |
Rule("operator", arity, precedence, predicate) body |
arity, precedence -- integers
predicate -- function returning boolean
body -- expression, body of rule
The arity for a rules database equals the number of arguments. Different rules data bases can be built for functions with the same name but with a different number of arguments.
Rules with a low precedence value will be tried before rules with a high value, so a rule with precedence 0 will be tried before a rule with precedence 1.
HoldArg("operator",parameter) |
parameter -- atom, symbolic name of parameter
The parameter must be an atom from the list of symbolic arguments used when calling RuleBase.
Retract("function",arity) |
arity -- positive integer
Assignment := of a function does this to the function being (re)defined.
UnFence("operator",arity) |
arity -- positive integers
The standard library functions For and ForEach use UnFence.
HoldArgNr("function", arity, argNum) |
arity, argNum -- positive integers
RuleBaseArgList("operator", arity) |
arity -- integer
Make sure that the arguments of Macro... commands evaluate to expressions that would normally be used in the non-macro versions!
`(expression) |
To invoke this functionality, a backquote ` needs to be placed in front of an expression. Parentheses around the expression are needed because the backquote binds tighter than other operators.
The expression should contain some variables (assigned atoms) with the special prefix operator @. Variables prefixed by @ will be evaluated even if they are inside function arguments that are normally not evaluated (e.g. functions declared with HoldArg). If the @var pair is in place of a function name, e.g. "@f(x)", then at the first stage of evaluation the function name itself is replaced, not the return value of the function (see example); so at the second stage of evaluation, a new function may be called.
One way to view backquoting is to view it as a parametric expression generator. @var pairs get substituted with the value of the variable var even in contexts where nothing would be evaluated. This effect can be also achieved using UnList and Hold but the resulting code is much more difficult to read and maintain.
This operation is relatively slow since a new expression is built before it is evaluated, but nonetheless backquoting is a powerful mechanism that sometimes allows to greatly simplify code.
In> Decl(f1,f2) := \ In> `(@f1(x_IsNumber) <-- N(@f2(x))); Out> True; In> Decl(nSin,Sin) Out> True; In> Sin(1) Out> Sin(1); In> nSin(1) Out> 0.8414709848; |
This example assigns the expression func(value) to variable var. Normally the first argument of Set would be unevaluated.
In> SetF(var,func,value) := \ In> `(Set(@var,@func(@value))); Out> True; In> SetF(a,Sin,x) Out> True; In> a Out> Sin(x); |
SetExtraInfo(expr,tag) GetExtraInfo(expr) |
tag -- tag information (any other expression)
The function SetExtraInfo returns the tagged expression, leaving the original expression alone. This means there is a common pitfall: be sure to assign the returned value to a variable, or the tagged expression is lost when the temporary object is destroyed.
The original expression is left unmodified, and the tagged expression returned, in order to keep the atomic objects small. To tag an object, a new type of object is created from the old object, with one added property (the tag). The tag can be any expression whatsoever.
The function GetExtraInfo(x) retrieves this tag expression from an object x. If an object has no tag, it looks the same as if it had a tag with value False.
No part of the Yacas core uses tags in a way that is visible to the outside world, so for specific purposes a programmer can devise a format to use for tag information. Association lists (hashes) are a natural fit for this, although it is not required and a tag can be any object (except the atom False because it is indistinguishable from having no tag information). Using association lists is highly advised since it is most likely to be the format used by other parts of the library, and one needs to avoid clashes with other library code. Typically, an object will either have no tag or a tag which is an associative list (perhaps empty). A script that uses tagged objects will check whether an object has a tag and if so, will add or modify certain entries of the association list, preserving any other tag information.
Note that FlatCopy currently does not copy the tag information (see examples).
In> a:=2*b Out> 2*b; In> a:=SetExtraInfo(a,{{"type","integer"}}) Out> 2*b; In> a Out> 2*b; In> GetExtraInfo(a) Out> {{"type","integer"}}; In> GetExtraInfo(a)["type"] Out> "integer"; In> c:=a Out> 2*b; In> GetExtraInfo(c) Out> {{"type","integer"}}; In> c Out> 2*b; In> d:=FlatCopy(a); Out> 2*b; In> GetExtraInfo(d) Out> False; |
GarbageCollect() |
Reference counting refers to bookkeeping where in each object a counter is held, keeping track of the number of parts in the system using that object. When this count drops to zero, the object is automatically removed. Reference counting is not the fastest way of doing garbage collection, but it can be implemented in a very clean way with very little code.
Among the most important objects that are not reference counted are the strings. GarbageCollect collects these and disposes of them when they are not used any more.
GarbageCollect is useful when doing a lot of text processing, to clean up the text buffers. It is not highly needed, but it keeps memory use low.
FindFunction(function) |
In> FindFunction("Sum") Out> "sums.rep/code.ys"; In> FindFunction("Integrate") Out> "integrate.rep/code.ys"; |
Secure(body) |