|
|
last edited 9 years ago by test1 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | ||
Editor: hemmecke
Time: 2014/02/14 09:12:27 GMT+0 |
||
Note: |
changed: - - SPAD programs are compiled to machine code by the SPAD compiler that comes with FriCAS. - SPAD programs are ordinary text files that will be compiled to machine code by the SPAD compiler that comes with FriCAS. changed: - We try not to rely on any previously defined library, but we prefix every constructor with 'My' We do not to rely on any previously defined library, but we prefix every constructor with 'My' changed: - Every constructor needs an ')abbrev' line where one specifies whether the constructore to come is Every constructor needs an ')abbrev' line where one specifies whether the constructor to come is changed: - Now we can use our little program. This above code for 'MyFun' can be in the same file as the code for 'MyMonoid', then one compilation would be enough. If, however, it is in another file 'myfun.spad', then a call to )compile myfun.spad indide a FriCAS session would be necessary. Now we can use our little program. For that, we enter a FriCAS session and type the following. added: Comments on the above program - SPAD distinguishes between '%' and 'Rep'. That's the reason for the definition of 'rep' and 'per' before 'MyFun'. The percent sign is a name for the current domain, it is comparable to 'this' or 'self' in other programming languages, but it does not denote the object, but rather its type, i.e., '%' stands for a domain. In the definition of 'MyFun', '%' basically stands for 'MyFun(S)'. In contrast to that, 'Rep' denotes the domain that the current domain inherits its data representation from (but not it's exports). The distinction between '%' and 'Rep' is in what they export. Whereas '%' exports all the functions that are listed in the category part of the domain, 'Rep' points to a previously defined domain and thus exports exactly what is given there. In our case 'Rep' is the same as <code>S -> S</code>. Whereas '%' exports <code>*</code>, 'Rep' does not. In contrast to that. 'Rep' exports 'elt', which allows to write 'f(s)' if 'f' is of type <code>S -> S</code> and 's' is of type 'S', i.e. one can apply 'f' to an argument of type 'S'. '%' and equally 'MyFun(S)' lack this export. That is the reason for the complicated looking expression (rep x)(rep y)(s) that just says 'f(g(s)' if 'f' and 'g' denote the functions, corresponding to 'x' and 'y', respectively. In other words, juxtaposition in FriCAS associates to the right and usually means function application. - Similar to Python, instead of braces, SPAD uses indentation to group code blocks. - The excape character in SPAD is an underscore, not a backslash. Currently, the '*' identifier in the definition of 'MyMonoid' must be escaped in that position. (There is hope that this need will go away in the future.) - The symbol '1' in the definition of 'MyMonoid' is not a number, but rather an identifier. Since in mathematics, '0' and '1' are used so often, both can be used as identifiers. - One usually writes 't: T' to denote that 't' is of type 'T', i.e. with :: _*: (%, %) -> % we declare that '*' is a function with two arguments of the same type, that returns a result of exactly this type. SPAD defines a few binary operators, like '+', '*', 'rem', 'mod' to be infix. Except those few functions, all functions are used in prefix form, though. - A category is defined by the following pattern:: C: Category == Join(C1,...,Cn) with f1: T1 ... fk: Tk where 'Join(...)' can be missing or just be a single category 'C1'. - A domain is defined by the following pattern:: D: C == A add Rep ==> A rep x ==> (x@%) pretend Rep per x ==> (x@Rep) pretend % f1: T1 == ... ... fk: Tk == ... where 'C' is a category and 'A' is a domain from which 'D' inherits. If a domain 'A' appears in front of the 'add' keyword, then 'D' inherits also all the implementations of the functions that are listed in the category part 'C'. - SPAD has macros. :: X ==> Y macro X == Y Both of the above lines are doing the same thing, they define a macro X that expands to Y whenever it appears elsewhere in the program code. Of course, only one of these lines would be sufficient. - The notation :: (s: S): S +-> .... is a way to denote lambda expression (unnamed functions). - The notation 'x @ X' means 'x' will be of type 'X'. That is rarely seen in SPAD, but since SPAD not only allows to distinguish functions by their input types, but also their output types, it is sometimes necessary. For example, in SPAD '=' is not builtin. It is an ordinary function of type :: (%, %) -> T where T can be different things. For example, the domain 'Integer' exports a function :: _=: (%, %) -> Boolean with the usual meaning of equality. However, there is another domain in FriCAS, namely 'Equation(Integer)' that exports a function :: _=: (Integer, Integer) -> % Now, without '@' it would be impossible to tell what the type of :: 42 = 7 is. It could be 'Boolean' or 'Equation(Integer)'. If the result should be of type 'Boolean', we write :: (42 = 7)@Boolean
42
, 3.14159265
, "abc"
, [3,5,11]
.
It is one one usually consideres as values in other programming languages.Integer
is a type for 42
, 3.14
is of type Float
,
"abc"
is of type String
, [1,2,4,8]
is of type List(Integer)
.Domains are comparable to classes in object oriented programming languages.
Integer
is of type IntegerNumberSystem
, String
is of type StringCategory
,
List(Integer)
is of type ListAggregate(Integer)
.Categories are somewhat comparable to interfaces in Java, but are much more powerful.
Category
.
In other words, IntegerNumberSystem
, StringCategory
, ListAggregate(Integer)
are of
type Category
.Record
, Tuple
, Join
, Mapping
(abbreviated via ->
).
Library defined are Integer
, List
, String
, Symbol
, Monoid
, Field
, etc. Let us start with a little program.
We do not to rely on any previously defined library, but we prefix every constructor with My
in order to avoid name conflicts with existing names.
Our goal is to provide a domain MyFun
that is parametrized by a domain S
and represents functions
from S into itself. We would like to be able to turn any function of type S -> S
into an element of the MyFun(S)
domain. Furthermore, we want to turn this domain into a
monoid MyMonoid
.
First we define the category MyMonoid
.
)abbrev category MYMON MyMonoid MyMonoid: Category == with 1: % _*: (%,%) -> %
Compiling FriCAS source code from file /var/lib/zope2.10/instance/axiom-wiki/var/LatexWiki/3904508595934233674-25px001.spad using old system compiler. MYMON abbreviates category MyMonoid ------------------------------------------------------------------------ initializing NRLIB MYMON for MyMonoid compiling into NRLIB MYMON
;;; *** |MyMonoid| REDEFINED Time: 0 SEC.
finalizing NRLIB MYMON Processing MyMonoid for Browser database: --->-->MyMonoid(constructor): Not documented!!!! --->-->MyMonoid(((One) (%) constant)): Not documented!!!! --->-->MyMonoid((* (% % %))): Not documented!!!! --->-->MyMonoid(): Missing Description ; compiling file "/var/aw/var/LatexWiki/MYMON.NRLIB/MYMON.lsp" (written 14 FEB 2014 09:12:26 AM):
; /var/aw/var/LatexWiki/MYMON.NRLIB/MYMON.fasl written ; compilation finished in 0:00:00.005 ------------------------------------------------------------------------ MyMonoid is now explicitly exposed in frame initial MyMonoid will be automatically loaded when needed from /var/aw/var/LatexWiki/MYMON.NRLIB/MYMON
Every constructor needs an )abbrev
line where one specifies whether the constructor to come is
a category or domain. Then follows a capitalized identifier of at most 7 characters and finally
the identifier for the constructor.
By convention, constructors begin with an uppercase letter and capitalize the first letter of each new word. Underscores are not commonly used.
Supposed the above code goes into a file mymonoid.spad
, then this file can be compiled via:
)compile mymonoid.spad
indide a FriCAS? session.
Now comes the corresponding domain definition.
rep x ==> (x@%) pretend Rep per x ==> (x@Rep) pretend %
)abbrev domain MYFUN MyFun MyFun(S: SetCategory): MyMonoid with myfun: (S -> S) -> % coerce: % -> (S -> S) == add Rep ==> S -> S myfun(f: S -> S): % == per f coerce(x: %): S -> S == rep x 1: % == per((s: S): S +-> s) ((x: %) * (y: %)): % == per( (s: S): S +-> (rep x)(rep y)(s) )
Compiling FriCAS source code from file /var/lib/zope2.10/instance/axiom-wiki/var/LatexWiki/2899365196648008240-25px002.spad using old system compiler. MYFUN abbreviates domain MyFun ------------------------------------------------------------------------ initializing NRLIB MYFUN for MyFun compiling into NRLIB MYFUN processing macro definition Rep ==> S -> S compiling exported myfun : S -> S -> $ MYFUN;myfun;M$;1 is replaced by f Time: 0.01 SEC.
compiling exported coerce : $ -> S -> S MYFUN;coerce;$M;2 is replaced by x Time: 0 SEC.
compiling exported One : () -> $ Time: 0 SEC.
compiling exported * : ($,$) -> $ Time: 0 SEC.
(time taken in buildFunctor: 0)
;;; *** |MyFun| REDEFINED
;;; *** |MyFun| REDEFINED Time: 0 SEC.
Cumulative Statistics for Constructor MyFun Time: 0.01 seconds
finalizing NRLIB MYFUN Processing MyFun for Browser database: --->-->MyFun(constructor): Not documented!!!! --->-->MyFun((myfun (% (Mapping S S)))): Not documented!!!! --->-->MyFun((coerce ((Mapping S S) %))): Not documented!!!! --->-->MyFun(): Missing Description ; compiling file "/var/aw/var/LatexWiki/MYFUN.NRLIB/MYFUN.lsp" (written 14 FEB 2014 09:12:26 AM):
; /var/aw/var/LatexWiki/MYFUN.NRLIB/MYFUN.fasl written ; compilation finished in 0:00:00.017 ------------------------------------------------------------------------ MyFun is now explicitly exposed in frame initial MyFun will be automatically loaded when needed from /var/aw/var/LatexWiki/MYFUN.NRLIB/MYFUN
This above code for MyFun
can be in the same file as the code for MyMonoid
,
then one compilation would be enough. If, however, it is in another file myfun.spad
,
then a call to
)compile myfun.spad
indide a FriCAS? session would be necessary.
Now we can use our little program. For that, we enter a FriCAS? session and type the following.
I ==> Integer
II ==> I -> I
inc(i: I): I == i+1
Function declaration inc : Integer -> Integer has been added to workspace.
double(i: I): I == 2*i
Function declaration double : Integer -> Integer has been added to workspace.
minc := myfun inc
Compiling function inc with type Integer -> Integer
LISP output: (#<FUNCTION |*1;inc;1;initial|>)
mdouble := myfun double
Compiling function double with type Integer -> Integer
LISP output: (#<FUNCTION |*1;double;1;initial|>)
f := (mdouble * minc) :: II
(1) |
g := (minc * mdouble) :: II
(2) |
f 1
(3) |
g 1
(4) |
%
and Rep
.
That's the reason for the definition of rep
and per
before MyFun
.
The percent sign is a name for the current domain, it is comparable to this
or self
in other programming languages, but it does not denote the object, but rather its type,
i.e., %
stands for a domain. In the definition of MyFun
, %
basically stands for MyFun(S)
.
In contrast to that, Rep
denotes the domain that the current domain inherits its
data representation from (but not it's exports).
The distinction between %
and Rep
is in what they export.
Whereas %
exports all the functions that are listed in the category part of the domain,
Rep
points to a previously defined domain and thus exports exactly what is given there.
In our case Rep
is the same as S -> S
. Whereas %
exports *
,
Rep
does not. In contrast to that. Rep
exports elt
, which allows to write f(s)
if f
is of type S -> S
and s
is of type S
, i.e. one can apply f
to
an argument of type S
. %
and equally MyFun(S)
lack this export.
That is the reason for the complicated looking expression
(rep x)(rep y)(s)
that just says f(g(s)
if f
and g
denote the functions, corresponding to x
and y
, respectively.
In other words, juxtaposition in FriCAS? associates to the right and usually means function application.
*
identifier in the definition of MyMonoid
must be escaped in that position.
(There is hope that this need will go away in the future.)1
in the definition of MyMonoid
is not a number, but rather an identifier.
Since in mathematics, 0
and 1
are used so often, both can be used as identifiers.t: T
to denote that t
is of type T
, i.e. with :
_*: (%, %) -> % we declare that '*' is a function with two arguments of the same type, that returns a result of exactly this type. SPAD defines a few binary operators, like '+', '*', 'rem', 'mod' to be infix. Except those few functions, all functions are used in prefix form, though.
C: Category == Join(C1,...,Cn) with f1: T1 ... fk: Tk where 'Join(...)' can be missing or just be a single category 'C1'.
D: C == A add Rep ==> A rep x ==> (x@%) pretend Rep per x ==> (x@Rep) pretend % f1: T1 == ... ... fk: Tk == ... where 'C' is a category and 'A' is a domain from which 'D' inherits. If a domain 'A' appears in front of the 'add' keyword, then 'D' inherits also all the implementations of the functions that are listed in the category part 'C'.
X ==> Y macro X == Y Both of the above lines are doing the same thing, they define a macro X that expands to Y whenever it appears elsewhere in the program code. Of course, only one of these lines would be sufficient.
(s: S): S +-> .... is a way to denote lambda expression (unnamed functions).
x @ X
means x
will be of type X
.
That is rarely seen in SPAD, but since SPAD not only allows to distinguish
functions by their input types, but also their output types, it is sometimes necessary. For example, in SPAD =
is not builtin. It is an ordinary function of type :
(%, %) -> T
where T can be different things. For example, the domain Integer
exports a function :
_=: (%, %) -> Boolean
with the usual meaning of equality. However, there is another domain in FriCAS?, namely
Equation(Integer)
that exports a function :
_=: (Integer, Integer) -> %
Now, without @
it would be impossible to tell what the type of :
42 = 7
is. It could be Boolean
or Equation(Integer)
.
If the result should be of type Boolean
, we write :
(42 = 7)@Boolean