|
|
last edited 8 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 01:07:38 GMT+0 |
||
Note: |
changed: - Examples are: '42', '3.14159265', '"abc"', '[3,5,11]'. Examples are: '42', '3.14159265', '"abc"', <code>[3,5,11]</code>. changed: - '"abc"' is of type 'String', '[1,2,4,8]' is of type 'List(Integer)'. '"abc"' is of type 'String', <code>[1,2,4,8]</code> is of type 'List(Integer)'. changed: - - - - SPAD programs are usually definitions of categories and domains whose functionality will later be used in an interactive session or by other definitions. - While categories define the exports of domains, i.e. which function are provided, domains themselves implement the corresponding functions. - Domains form a type hierarchy where only inheritance from **one** other domain is allowed. - Categories form a type hierarchy with a multiple inheritance mechanism. - Categories and domains are often called constructors and (as shown above) can be parametrized. - SPAD has only very few built-in constructors. Most of the constructors are defined in a library. Builtin are 'Record', 'Tuple', 'Join', 'Mapping' (abbreviated via <code>-></code>). Library defined are 'Integer', 'List', 'String', 'Symbol', 'Monoid', 'Field', etc. A running example Let us start with a little program. We try 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 <code>S -> S</code> 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'. changed: -)abbrev domain MINI MinimalInitialNotIntegrated -MinimalInitialNotIntegrated(x,F): Exports == Implementation where - x: Symbol - F: Field - - INT ==> Integer - P ==> UnivariatePolynomial(x,F) - FRP ==> Fraction P - LFRP ==> List FRP - - Exports == with - - degreeX: % -> INT - - Implementation == add - - Rep := LFRP - - degreeX f == - a := [denom i for i in f::Rep]@List(P) -- denom : FRAC UP -> UP(x,F) - b := map(di +-> degree(di), a)$ListFunctions2(P, INT) -- degree : UP -> NonNegativeInteger - --b := [degree i for i in a ] - reduce( max, b ,0) :: INT )abbrev category MYMON MyMonoid MyMonoid: Category == with 1: % _*: (%, %) -> % added: Every constructor needs an ')abbrev' line where one specifies whether the constructore 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. \begin{spad} rep x ==> (x@%) pretend Rep per x ==> (x@Rep) pretend % )abbrev category MYMON MyMonoid XHashTable(Key : SetCategory, Entry : Type): Join(TableAggregate(Key, Entry), finiteAggregate, shallowlyMutable) with table : (Key -> SingleInteger) -> % ++ table(h) creates an empty hash table that uses h instead of ++ hash$Key. Note that h should be a mathematical function in ++ the sense that from k1=k2 follows h(k1)=h(k2). If that is not ++ the case, k1 and k2 will internally be considered as being ++ different keys. == add Marker ==> None toMarker mk ==> mk@Marker -- note that MKey==Marker==UMKE VACANT : Marker := (HASHTABLEVACANT$Lisp) pretend Marker -- pos never used DELETED : Marker := (HASHTABLEDELETED$Lisp) pretend Marker -- pos is deleted vacant?(mk) ==> EQ(toMarker mk, VACANT)$Lisp deleted?(mk) ==> EQ(toMarker mk, DELETED)$Lisp key?(mk) ==> not (vacant? mk or deleted? mk) MKey ==> None UMKE ==> None Buckets ==> PrimitiveArray UMKE numOfBuckets(a) ==> shift(#a, -1) toUMKE x ==> x pretend UMKE toKey k ==> (k@UMKE) pretend Key getMKey(a, i) ==> ((a.i)@UMKE) pretend MKey setKey!(a, i, k) ==> (a.i := toUMKE k) pretend Key getEntry(a, n, i) ==> a(n+i) pretend Entry setEntry!(a, n, i, e) ==> (a(n+i) := toUMKE e) pretend Entry setKeyEntry!(a, n, i, k, e) ==> (setKey!(a, i, k); setEntry!(a, n, i, e)) -- deleteKeyEntry!(a, n, i) ==> setKeyEntry!(a, n, i, DELETED, VACANT) deleteKeyEntry!(a, n, i) ==> (a.i := toUMKE DELETED; a(n+i) := toUMKE VACANT) KE ==> Record(key : Key, entry : Entry) UE ==> Union(Entry, "failed") maxLoad n ==> n*7 quo 10 -- load factor maxVirtualLoad n ==> n*9 quo 10 -- virtual load factor Rep ==> Record(_ numOfEntries : Z, _ maxNumOfEntries : Z, _ numOfDeletedEntries : Z, _ maxNumOfVirtualEntries : Z, _ idx : Z, _ arr : Buckets, _ hashFunction : Key -> I) localSearch(a : Buckets, k : Key, h : Key -> I) : Z == n : Z := numOfBuckets a h1 : Z := (h k)::Z p : Z := positiveRemainder(h1, n) -- position in array h2 : Z := 1 + positiveRemainder(h1, n-2) mk : MKey := getMKey(a, p) deletedPosition? : Boolean := false while not vacant? mk repeat deleted? mk => (deletedPosition? := true; break) k = toKey mk => return p -- key found p := p + h2 if p>=n then p := p-n mk := getMKey(a, p) q := p -- first position of a free entry -- We ignore DELETED entries when looking for the key. while not vacant? mk repeat not deleted? mk and k = toKey mk => setKeyEntry!(a, n, q, k, getEntry(a, n, p)) deleteKeyEntry!(a, n, p) return q -- entry has been copied to previous DELETED position p := p + h2 if p>=n then p := p-n mk := getMKey(a, p) if deletedPosition? then q := q-n q-n -- KEY not found. \end{spad}
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 try 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 01:07:38 AM):
; /var/aw/var/LatexWiki/MYMON.NRLIB/MYMON.fasl written ; compilation finished in 0:00:00.006 ------------------------------------------------------------------------ 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 constructore 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.
rep x ==> (x@%) pretend Rep per x ==> (x@Rep) pretend %
)abbrev category MYMON MyMonoid XHashTable(Key : SetCategory,Entry : Type): Join(TableAggregate(Key, Entry), finiteAggregate, shallowlyMutable) with table : (Key -> SingleInteger) -> % ++ table(h) creates an empty hash table that uses h instead of ++ hash$Key. Note that h should be a mathematical function in ++ the sense that from k1=k2 follows h(k1)=h(k2). If that is not ++ the case, k1 and k2 will internally be considered as being ++ different keys. == add Marker ==> None toMarker mk ==> mk@Marker -- note that MKey==Marker==UMKE VACANT : Marker := (HASHTABLEVACANT$Lisp) pretend Marker -- pos never used DELETED : Marker := (HASHTABLEDELETED$Lisp) pretend Marker -- pos is deleted vacant?(mk) ==> EQ(toMarker mk, VACANT)$Lisp deleted?(mk) ==> EQ(toMarker mk, DELETED)$Lisp key?(mk) ==> not (vacant? mk or deleted? mk) MKey ==> None UMKE ==> None Buckets ==> PrimitiveArray UMKE numOfBuckets(a) ==> shift(#a, -1) toUMKE x ==> x pretend UMKE toKey k ==> (k@UMKE) pretend Key getMKey(a, i) ==> ((a.i)@UMKE) pretend MKey setKey!(a, i, k) ==> (a.i := toUMKE k) pretend Key getEntry(a, n, i) ==> a(n+i) pretend Entry setEntry!(a, n, i, e) ==> (a(n+i) := toUMKE e) pretend Entry setKeyEntry!(a, n, i, k, e) ==> (setKey!(a, i, k); setEntry!(a, n, i, e)) -- deleteKeyEntry!(a, n, i) ==> setKeyEntry!(a, n, i, DELETED, VACANT) deleteKeyEntry!(a, n, i) ==> (a.i := toUMKE DELETED; a(n+i) := toUMKE VACANT) KE ==> Record(key : Key, entry : Entry) UE ==> Union(Entry, "failed") maxLoad n ==> n*7 quo 10 -- load factor maxVirtualLoad n ==> n*9 quo 10 -- virtual load factor Rep ==> Record(_ numOfEntries : Z, _ maxNumOfEntries : Z, _ numOfDeletedEntries : Z, _ maxNumOfVirtualEntries : Z, _ idx : Z, _ arr : Buckets, _ hashFunction : Key -> I) localSearch(a : Buckets, k : Key, h : Key -> I) : Z == n : Z := numOfBuckets a h1 : Z := (h k)::Z p : Z := positiveRemainder(h1, n) -- position in array h2 : Z := 1 + positiveRemainder(h1, n-2) mk : MKey := getMKey(a, p) deletedPosition? : Boolean := false while not vacant? mk repeat deleted? mk => (deletedPosition? := true; break) k = toKey mk => return p -- key found p := p + h2 if p>=n then p := p-n mk := getMKey(a, p) q := p -- first position of a free entry -- We ignore DELETED entries when looking for the key. while not vacant? mk repeat not deleted? mk and k = toKey mk => setKeyEntry!(a, n, q, k, getEntry(a, n, p)) deleteKeyEntry!(a, n, p) return q -- entry has been copied to previous DELETED position p := p + h2 if p>=n then p := p-n mk := getMKey(a, p) if deletedPosition? then q := q-n q-n -- KEY not found.
Compiling FriCAS source code from file /var/lib/zope2.10/instance/axiom-wiki/var/LatexWiki/4783886012475744616-25px002.spad using old system compiler. MYMON abbreviates category MyMonoid ------------------------------------------------------------------------ initializing NRLIB XHASHTBL for XHashTable compiling into NRLIB XHASHTBL processing macro definition Marker ==> None processing macro definition toMarker mk ==> @(mk,None) processing macro definition vacant? mk ==> (elt Lisp EQ)(@(mk, None), VACANT) processing macro definition deleted? mk ==> (elt Lisp EQ)(@(mk, None), DELETED) processing macro definition key? mk ==> SEQ(LET(G660, (elt Lisp EQ)(@(mk, None), VACANT)), exit(1, IF(G660, false, SEQ(LET(G661, (elt Lisp EQ)(@(mk, None), DELETED)), exit(1, IF(G661, false, true)))))) processing macro definition MKey ==> None processing macro definition UMKE ==> None processing macro definition Buckets ==> PrimitiveArray None processing macro definition numOfBuckets a ==> shift(# a, - One) processing macro definition toUMKE x ==> pretend(x, None) processing macro definition toKey k ==> pretend(@(k, None), Key) processing macro definition getMKey(a, i) ==> pretend(@(a i, None), None) processing macro definition setKey!(a, i, k) ==> pretend(LET(a i, pretend(k, None)), Key) processing macro definition getEntry(a, n, i) ==> pretend(a +(n, i), Entry) processing macro definition setEntry!(a, n, i, e) ==> pretend(LET(a +(n, i), pretend(e, None)), Entry) processing macro definition setKeyEntry!(a, n, i, k, e) ==> SEQ(pretend(LET(a i, pretend(k, None)), Key), exit(1, pretend(LET(a +(n, i), pretend(e, None)), Entry))) processing macro definition deleteKeyEntry!(a, n, i) ==> SEQ(LET(a i, pretend(DELETED, None)), exit(1, LET(a +(n, i), pretend(VACANT, None)))) processing macro definition KE ==> Record(key: Key, entry: Entry) processing macro definition UE ==> Union(Entry, failed) processing macro definition maxLoad n ==> quo(*(n, 7), 10) processing macro definition maxVirtualLoad n ==> quo(*(n, 9), 10) processing macro definition Rep ==> Record(numOfEntries: Z, maxNumOfEntries: Z, numOfDeletedEntries: Z, maxNumOfVirtualEntries: Z, idx: Z, arr: PrimitiveArray None, hashFunction: Key -> I) compiling local localSearch : (PrimitiveArray None, Key, Key -> I) -> Z Semantic Errors: [1] Z is not a known type [2] localSearch: Z is not a known type
Warnings: [1] pretend(None) -- should replace by @
****** comp fails at level 2 with expression: ****** error in function localSearch
(SEQ | << | (LET (|:| |n| Z) (|shift| (|#| |a|) (- 1))) | >> | (LET (|:| |h1| Z) (|::| (|h| |k|) Z)) (LET (|:| |p| Z) (|positiveRemainder| |h1| |n|)) (LET (|:| |h2| Z) (+ 1 (|positiveRemainder| |h1| (- |n| 2)))) (LET (|:| |mk| (|None|)) (|pretend| (@ (|a| |p|) (|None|)) (|None|))) (LET (|:| |deletedPosition?| (|Boolean|)) |false|) (REPEAT (WHILE (SEQ (LET #1=#:G662 ((|elt| |Lisp| EQ) (@ |mk| (|None|)) VACANT)) (|exit| 1 (IF #1# |false| |true|)))) (SEQ (LET #2=#:G663 ((|elt| |Lisp| EQ) (@ |mk| (|None|)) DELETED)) (|exit| 1 (IF #2# (SEQ (LET |deletedPosition?| |true|) (|exit| 1 (|leave| 1 |$NoValue|))) (SEQ (LET #3=#:G664 (= |k| (|pretend| (@ |mk| (|None|)) |Key|))) (|exit| 1 (IF #3# (|return| 1 |p|) (SEQ (LET |p| (+ |p| |h2|)) (IF (>= |p| |n|) (LET |p| (- |p| |n|)) |noBranch|) (|exit| 1 (LET |mk| (|pretend| (@ (|a| |p|) (|None|)) (|None|)))))))))))) (LET |q| |p|) (REPEAT (WHILE (SEQ (LET #4=#:G665 ((|elt| |Lisp| EQ) (@ |mk| (|None|)) VACANT)) (|exit| 1 (IF #4# |false| |true|)))) (SEQ (SEQ (LET #5=#:G666 ((|elt| |Lisp| EQ) (@ |mk| (|None|)) DELETED)) (|exit| 1 (IF #5# |noBranch| (SEQ (LET #6=#:G667 (= |k| (|pretend| (@ |mk| (|None|)) |Key|))) (|exit| 1 (IF #6# (|exit| 3 (SEQ (SEQ (|pretend| (LET (|a| |q|) (|pretend| |k| (|None|))) |Key|) (|exit| 1 (|pretend| (LET (|a| (+ |n| |q|)) (|pretend| (|pretend| (|a| (+ |n| |p|)) |Entry|) (|None|))) |Entry|))) (SEQ (LET (|a| |p|) (|pretend| DELETED (|None|))) (|exit| 1 (LET (|a| (+ |n| |p|)) (|pretend| VACANT (|None|))))) (|exit| 1 (|return| 1 |q|)))) |noBranch|)))))) (LET |p| (+ |p| |h2|)) (IF (>= |p| |n|) (LET |p| (- |p| |n|)) |noBranch|) (|exit| 1 (LET |mk| (|pretend| (@ (|a| |p|) (|None|)) (|None|)))))) (IF |deletedPosition?| (LET |q| (- |q| |n|)) |noBranch|) (|exit| 1 (- |q| |n|))) ****** level 2 ****** $x:= (LET (: n Z) (shift (# a) (- (One)))) $m:= NoValueMode $f:= ((((|h| # #) (|k| # #) (|a| # #) (|localSearch| #) ...)))
>> Apparent user error: CANNOT ASSIGN: (shift (# a) (- (One))) OF MODE: (NonNegativeInteger) TO: n OF MODE: Z