MathGroup Archive 2003

[Date Index] [Thread Index] [Author Index]

Search the Archive

OOP experiments in Mathematica- The Stack

  • To: mathgroup at smc.vnet.net
  • Subject: [mg38656] OOP experiments in Mathematica- The Stack
  • From: "Steve S. Shaw" <steve at shawstudio.com>
  • Date: Fri, 3 Jan 2003 00:15:51 -0500 (EST)
  • Sender: owner-wri-mathgroup at wolfram.com

A series of OOP experiments in Mathematica.
msg#2 - The Stack, part#1: Mathematics of a stack.

Having listed Goals and References in msg#1,
(post 4 of thread "Re: Re: OOP in Mathematica" on 30-Dec-2002),
now consider one small example using OOP.


-----------------------------------------------------------------
----- A classic programming task - a stack -----


-----------------------------------------------------------------
Mathematics of a stack, based on:
[Meyer-97] Ch. 6. Abstract data types.
sec. 6.1-6.4 gives an "abstract data type" prescription for a stack.

- - - - -
Brief explanation of syntax:

* "STACK"   -- type names are all-capitals.

* "ANY"     -- like "Object" in Java

* "new() -> STACK" -- function named 'new' takes no parameters,
       and returns a stack.

* "push( STACK, ANY ) -> STACK"  -- function named 'push',
       takes two parameters: (a stack) and (any object), and returns a
stack.

NOTE: this doesn't explain what push does, it just declares what object
types come in and out of the function.  This is a pure-functional
(no-side-effect) mathematical specification - so any change is shown by
creating a new object, rather than modifying an existing object.

In the OO languages, for a "mutable" type "Stack",
"STACK in and STACK out" will be turned into a single STACK that is changing
state.

The actual behavior of the functions is determined implicitly from the
axioms that come later.

* "drop( STACK ) -> STACK
   drop( s ) require not empty( s )"  -- function named 'drop',
       takes a stack and returns a stack.  This will become an action that
changes the state of a stack.
       The "require" part is a condition - this function must only be called
with a non-empty stack.

-----------------------------------
--- Mathematics of a stack ---

For any "x" of type "ANY" and "s" of type "STACK"...

Type:
  STACK

Type-signatures of FUNCTIONS with PRECONDITIONS:

* new() -> STACK

* isEmpty( STACK ) -> BOOLEAN

* push( STACK, ANY ) -> STACK

* top( STACK ) -> ANY
  top( s ) require not isEmpty( s )

* drop( STACK ) -> STACK
  drop( s ) require not isEmpty( s )


Axioms:

A1. isEmpty( new() ) = True

A2. isEmpty( push( s, x ) ) = False

A3. top( push( s, x ) ) = x

A4. drop( push( s, x ) ) = s
-----------------------------------

Informally, this is saying:

A1. "new()" creates an empty stack.

A2. After "push", a stack is not empty.

A3. "push( s, x )" causes 'x' to now be "top" of stack.

A4. "push" followed by "drop" returns the stack as it was before the push.

Combining these axioms, produces all the desired behavior of a stack.

For example:
  top( push( new(), x1 ) ) = x1
  top( push( push( new(), x1 ), x2 ) = x2
  top( drop( push( push( new(), x1 ), x2 ) ) ) ) = x1

Because PRECONDITIONS are specified,
we can also discover ILLEGAL operations on a stack:

  top( new() )
=> ERROR "top( s ) require not isEmpty( s )"

  drop( drop( push ( new(), x1 ) ) )
=> ERROR "drop( s ) require not isEmpty( s )"


NOTE: wondering where "pop()" is?
That is a compound action.
"pop( s )" is equivalent to:
" temp = top( s )
  drop( s )
  return temp"


-----------------------------------------------------------------
Here is that mathematical spec, as it might be shown in Mathematica:

NOTE: Since this example doesn't involve "inheritance", it can be modeled
using a simple type.  That is, by having the "head" of an expression be
"STACK".

NOTE: "conditions" aren't yet shown.

(*-- Functions of a stack --*)
new[]
isEmpty[ s_STACK ]
push[ s_STACK, x_ ]
top[ s_STACK ]
drop[ s_STACK ]

(*-- Axioms of a stack.  True for any s & x. --*)
axiom1[]:=isEmpty[ new[] ];
axiom2[ s_STACK, x_ ]:=!isEmpty[ push[ s, x ] ];
axiom3[ s_STACK, x_ ]:=(top[ push[ s,x ] ]==x);
axiom4[ s_STACK, x_ ]:=(drop[ push[ s,x ] ]==s);
allAxioms[ s_STACK, x_ ]:=(
      axiom1[] && axiom2[ s,x ] && axiom3[ s,x ] &&  axiom4[ s,x ]);


-----------------------------------------------------------------
What's Next:

Showing implementations in Eiffel, then Java.

Then finally, Mathematica implementations.
(The above Mathematica code isn't an implementation,
 as I don't show definitions for the 5 "functions of a stack".
 The idea is that many different implementations should be possible.
 But all a client should know, is what I have shown above.
 Plus the "pre-conditions", that I haven't yet shown in Mathematica.
)

Since I am coming from an OO background, I may not be showing the most
"natural" Mathematica implementations.  Though in this simple case (before
getting into "inheritance"), hopefully I will be close to the mark.

-- Steve S. Shaw (ToolmakerSteve)




  • Prev by Date: Re: Re: OOP in Mathematica
  • Next by Date: Re: Solving Alphametics with Mathematica
  • Previous by thread: Re: OOP experiments in Mathematica- The Stack
  • Next by thread: Re: OOP experiments in Mathematica- The Stack