[comp.ai] posting of sources from AI Expert Magazine for March '87

turner@imagen.UUCP (02/24/87)

#! /bin/sh
# This is a shell archive, meaning:
# 1. Remove everything above the #! /bin/sh line.
# 2. Save the resulting text in a file.
# 3. Execute the file with /bin/sh (not csh) to create:
#	actor.mar
#	contnt.mar
#	expert.mar
#	files.mar
#	logo.mar
# This archive created: Mon Feb 23 15:33:29 1987
# By:	D'arc Angel (The Houses of the Holy)
export PATH; PATH=/bin:/usr/bin:$PATH
echo shar: "extracting 'actor.mar'" '(3017 characters)'
if test -f 'actor.mar'
then
	echo shar: "will not over-write existing file 'actor.mar'"
else
cat << \SHAR_EOF > 'actor.mar'


                        "Actor Goes on Stage"
                         by Andrew P. Bernat
                         March 1987 AI EXPERT


Listing 1.  
A Comparison of ACTOR and Smalltalk-80



          /*  ACTOR solution to Towers of Hanoi  */ 
          /*  Create a new class named TowerOfHanoi to handle the problem.
              The new class is directly beneath Object in the hierarchy;
              Object being at the top of the class hierarchy.*/
          inherit(Object, #TowerOfHanoi, nil, nil, nil);
          /*  Here we set the compiler's curClass instance variable,
              which specifies which class the following messages are to
              apply to. */
          Compiler.curClass := TowerOfHanoi;
          /*  Define a new message named moveTower */
          Def moveTower(self, height, from, to, use) 
          {  if height > 0 
             then  moveTower(self, height - 1, from, use, to); 
                moveDisk(self, from, to); 
                moveTower(self, height - 1, use, to, from); 
             endif; 
          } 
          /*  Define a new message named moveDisk */
          Def moveDisk(self, from, to) 
          {  eol(ThePort); 
             print(from); print("->"); print(to); 
          } 
          /*  Add a new member of class Object to the system dictionary,
              which is also named Actor, at key location sample */
          Actor[#sample] := new(Object);
          /*  Send message moveTower to the object sample.  sample, being
              of class Object, will respond using the code defined above.
              The parameters say to use three disks, and move them from
              tower 1 to tower 3 using tower 2 */
          moveTower(sample, 3, 1, 3, 2); 

          "  Tower of Hanoi code as implemented in Smalltalk/V.  Note that
             these messages and methods would be implemented directly
             through the System Browser. "
          "  Declare a new sublcass of Object."
          Object subclass: #TowerOfHanoi
          "  Instance variables would be declared here, but none are
             needed. "
           TowerOfHanoi methods
          "  Declare the moveTower message. "
             moveTower: height 
                  from: ftower to: ttower using: utower
               (> height 0)
                ifTrue: [self moveTower: height - 1 
                              from: ftower to: utower using: ttower.
                         self moveDisk: ftower to: ttower.
                         self moveTower: height - 1
                              from: utower to: ttower using: ftower]
          "  Declare the moveDisk message.  Transcript is a the standard
             output window."
            moveDisk: ftower to: ttower
              Transcript cr.
              Transcript show: ftower.
              Transcript show: '->'.
              Transcript show: ttower.  
          "  To execute, evaluate 
             (new TowerOfHanoi) moveTower: 3 from: 1 to: 3 using: 2"
           
SHAR_EOF
if test 3017 -ne "`wc -c < 'actor.mar'`"
then
	echo shar: "error transmitting 'actor.mar'" '(should have been 3017 characters)'
fi
fi
echo shar: "extracting 'contnt.mar'" '(2489 characters)'
if test -f 'contnt.mar'
then
	echo shar: "will not over-write existing file 'contnt.mar'"
else
cat << \SHAR_EOF > 'contnt.mar'

                         Table of Contents
                        AI EXPERT Magazine
                            March 1987
                   Theme:  Intelligent Data Bases


ARTICLES

Object-oriented Data Base Design                       
by Bob Peterson

The object-oriented data model is the natural result of the union 
of two technologies: object-oriented programming and database 
management. This article discusses the idea of object-oriented 
databases, contrasting this new development with classical 
approaches to data management.  


Intelligent Data Bases and Nial                
by M. A. Jenkins

Here we describe an architecture for an intelligent decision 
support system designed within a single language framework called 
the Nested Interactive Array Language (NIAL) -- which combines 
ideas from LISP, APL, Pascal, and logic programming into one 
coherent system.  


On Stage with Actor
by Andrew P. Bernat

ACTOR is a new programming language intended to make the 
flexibility and power of the object-oriented programming style 
even more available to microcomputer users.  Comparing Actor to 
Digitalk's Smalltalk/V, we will look at how well Actor meets the 
the goal of bringing the power of object-oriented programming 
down to the PC.  


Learn Logo Before LISP
by Michael McMillan 

This author suggests a novel way to learn LISP that will give the 
student a solid backround in symbolic computation -- learn LOGO 
first!  He claims that Logo has been the victim of its own 
success as an educational language, and contends that it can also 
be important to the 'grown-up world' of computer science and 
artificial intelligence.


DEPARTMENTS

Brain Waves           
Larry Harris, C.E.O., Artificial Intelligence Corp.
"The Marriage of AI and Data Base Technology"

AI Insider                                             
by Susan Shepard

Expert's Toolbox                                       
"Heuristic State Space Search"
by Marc Rettig

AI Apprentice                                         
"Breaking with Tradition:  Nonlinear Reading"
by Beverly and Bill Thompson

In Practice                                            
"The Making of a Tax Expert"
by Harvey Newquist                                 

Book Store           
"Machine Learning, Soar, and the Art of PROLOG"                                  
by Dr. Lance B. Eliot

Software Reviews:

LISP on the Micro, Part II:  
by Susan Shepard, et. al.

Personal Consultant Plus
by Susan Shepard

SHAR_EOF
if test 2489 -ne "`wc -c < 'contnt.mar'`"
then
	echo shar: "error transmitting 'contnt.mar'" '(should have been 2489 characters)'
fi
fi
echo shar: "extracting 'expert.mar'" '(7056 characters)'
if test -f 'expert.mar'
then
	echo shar: "will not over-write existing file 'expert.mar'"
else
cat << \SHAR_EOF > 'expert.mar'

                 Expert's Toolbox -- March 1987
                 "Heuristic State Space Search"
                         by Marc Rettig

                        Listings 1 and 2



Listing 1

; STATE-SPACE SEARCH PROCEDURE
;   These functions provide a general control structure for
; solving problems using heuristic search.  In order to apply
; this method to a particular problem, you must write the
; functions: initial-state, goal, successors, and print-solution.
;    See the "Expert's Toolbox" column in the March AI-Expert
; for a description of this algorithm and an example of its use.
;
; Algorithm given by Dr. Ralph Grishman, New York University,
; after Nils Nilsson, "Principles of Artificial Intelligence".
; Adapted for Xlisp by Marc Rettig (76703,1037).

(defun search ()
    (prog (open closed n m successor-list same)

          ; Step 1. Put initial state on open.
          (setq open (list (initial-state)))

          ; Step 2. If open is empty, exit with failure.
     expand:
          (cond ((null open) (print 'failure) (return nil)))

          ; Step 3. Remove state from open with minimum g + h and
          ;    call it n.  (open is sorted by increasing g + h, so
          ;    this is first element.)  Put n on closed.
          ;    Exit with success if n is a goal node.
          (setq n (car open))
          (setq open (cdr open))
          (setq closed (cons n closed))
          (trace 'expanding n)
          (cond ((goal n) (print-solution n) (return t)))

          ; For each m in successors(m):
          (setq successor-list (successors n))
     next-successor:
          (cond ((null successor-list) (go expand:)))
          (setq m (car successor-list))
          (setq successor-list (cdr successor-list))
          (trace 'successor m)
          (cond ((setq same (find m open))
                 ; if m is on open, reset g if new value is smaller
                 (cond
                  ((< (get m 'g) (get same 'g))
                   (setq open (add m (remove same open))))))
                ((setq same (find m closed))
                 ; If m is on closed and new value of g is smaller,
                 ; remove state from closed and add it to open with new g.
                 (cond
                  ((< (get m 'g) (get same 'g))
                   (setq closed (remove same closed))
                   (setq open (add m open)))))
                (t 
                  ; else add m to open
                  (setq open (add m open))))
          (go next-successor:)))

(defun add (state s-list)
    ; Inserts state into s-list so that list remains ordered
    ; by increasing g + h.
    (cond ((null s-list) (list state))
          ((> (+ (get (car s-list) 'g) (get (car s-list) 'h))
              (+ (get state 'g) (get state 'h)))
           (cons state s-list))
          (t (cons (car s-list) (add state (cdr s-list))))))

(defun find (state s-list)
    ; returns first entry on s-list whose position is same
    ; as that of state.
    (cond ((null s-list) nil)
          ((equal (get state 'position)
                  (get (car s-list) 'position))
           (car s-list))
          (t (find state (cdr s-list)))))



Listing 2

;  M I S S I O N A R I E S   A N D   C A N N I B A L S
;
;  The following routines, when used in conjunction with the state-space
;  search procedure, solve the missionaries and cannibals problem.  Three
;  missionaries and 3 cannibals are located on the right bank of a river,
;  along with a two-man rowboat.  We must find a way of moving all the
;  missionaries and cannibals to the left bank.  However, if at any time
;  there are more cannibals than missionaries on a bank, the cannibals will
;  exhibit a consuming interest in the misssionaries;  this must be avoided.
;
;  Each state is represented by an atom with the following properties:
;  	position -- a list of three elements,
;		the number of missionaries on the right bank
;		the number of cannibals on the right bank
;		the position of the boat (left or right)
;	g       -- the estimated g for that state
;	h       -- the estimated h (value of function heuristic) 
;	parent  -- the preceding state on the path from the initial state
;	            (the preceding state which gives rise to the least g,
;                        if there are several)

(defun initial-state ()
  ;  return the initial state
  (build-state 3 3 'right 0 nil))

(defun successors (state)
  ;  returns the successors of state
  ;  note that procedure try uses state and new-g, and modifies suc
  (prog (m c boat new-g suc)  
	;  extract parameters of current position and put in m, c, and boat
	(setq m (car (get state 'position)))
	(setq c (cadr (get state 'position)))
	(setq boat (caddr (get state 'position)))
	;  g of new state = g of old state + 1 (all crossings are unit cost)
	(setq new-g (+ 1 (get state 'g)))
	(cond ((equal boat 'right)
	       (try (- m 2) c 'left new-g)
	       (try (- m 1) c 'left new-g)
	       (try (- m 1) (- c 1) 'left new-g)
	       (try m (- c 1) 'left new-g)
	       (try m (- c 2) 'left new-g))
	      (t  ; boat is on left
	       (try (+ m 2) c 'right)
	       (try (+ m 1) c 'right)
	       (try (+ m 1) (+ c 1) 'right)
	       (try m (+ c 1) 'right)
	       (try m (+ c 2) 'right)))
	(return suc)))

(defun try (new-m new-c new-boat new-g)
  ;  if position(new-m,new-c,new-boat) is valid, add new state to suc
  (cond ((valid new-m new-c)
	 (setq suc (cons (build-state new-m new-c new-boat new-g state)
			 suc)))))

(defun valid (miss cann)
  ;  returns true if having 'miss' missionaries and 'cann' cannibals
  ;  on the right bank is a valid state
  (and (>= miss 0)
       (>= cann 0)
       (< miss 4)
       (< cann 4)
       (or (zerop miss) (>= miss cann))
       (or (zerop (- 3 miss)) (>= (- 3 miss) (- 3 cann)))))

(defun build-state (miss cann boat g parent)
  ;  creates a new state with parameters as specified by argument list
  (prog (newstate)
	(setq newstate (gensym))
	(putprop newstate (list miss cann boat) 'position)
	(putprop newstate g 'g)
	(putprop newstate (heuristic miss cann boat) 'h)
	(putprop newstate parent 'parent)
	(return newstate)))

(defun heuristic (miss cann boat)
  ;  our heuristic (h) function
  (cond ((equal boat 'left)
	 (* 2 (+ miss cann)))
	(t  ;  boat is on right
	 (* 2 (max 0 (+ miss cann -2))))))

(defun goal (state)
  ;  returns true if state is a goal state (no missionaries or cannibals on right)
  (and (zerop (car (get state 'position)))
       (zerop (cadr (get state 'position)))))

(defun print-solution (state)
  ;  invoked by search algorithm with goal state,
  ;  prints sequence of states from initial state to goal.
  (cond ((null state)
	  (print 'solution:))
	 (t
	  (print-solution (get state 'parent))
	  (print (get state 'position))
	 ))
)

(defun trace (comment state)
  ; if trace-switch is true, print out comment and position
  ; associated with state
  (cond 
    (trace-switch
      (print `(,comment state ,state with position ,(get state 'position)
               h(x) =  ,(get state 'h))))))

SHAR_EOF
if test 7056 -ne "`wc -c < 'expert.mar'`"
then
	echo shar: "error transmitting 'expert.mar'" '(should have been 7056 characters)'
fi
fi
echo shar: "extracting 'files.mar'" '(751 characters)'
if test -f 'files.mar'
then
	echo shar: "will not over-write existing file 'files.mar'"
else
cat << \SHAR_EOF > 'files.mar'


               Articles and Departments that have
                    Additional On-Line Files 

                            AI EXPERT
                           March 1987
                     "Intelligent Data Bases"
           (Note:  Contents page is in file CONTNT.MAR)




ARTICLES                                        RELEVANT FILES
--------                                        --------------  

March Table of Contents                           CONTNT.MAR

Actor Goes on Stage                               ACTOR.MAR
by Andrew P. Bernat

Learn LOGO Before LISP                            LOGO.MAR
by Mike McMillan

DEPARTMENTS

Expert's Toolbox                                  EXPERT.MAR
"Heuristic State Space Search"
by Marc Rettig

SHAR_EOF
if test 751 -ne "`wc -c < 'files.mar'`"
then
	echo shar: "error transmitting 'files.mar'" '(should have been 751 characters)'
fi
fi
echo shar: "extracting 'logo.mar'" '(7528 characters)'
if test -f 'logo.mar'
then
	echo shar: "will not over-write existing file 'logo.mar'"
else
cat << \SHAR_EOF > 'logo.mar'


                      Learn LOGO Before LISP
                         by Mike McMillan
                  March 1987 issue of AI EXPERT

                      Sidebars 1, 2, and 3


Sidebar 1

The following is a list of the LISP primitives,  predicates, 
functions and their Logo equivalents. Those functions that do not 
have  a  Logo  equivalent  have been noted.  Please remember that 
most,  if not all,  of the LISP functions that are not duplicated 
in Logo can be written in Logo. Logo is powerful enough to create 
functions that behave like their LISP equivalents.


The  LISP  function  is  listed first,  followed by the Logo 
equivalent or N/A, meaning Logo does not have that function.

          CAR - FIRST                        GET - GETPROP

          CDR - BUTFIRST                     PUTPROP - PUTPROP

          CXXXR - FIRST BUTFIRST...BUTFIRST  REMPROP - REMPROP

          LAST - LAST                        PLIST - PLIST

          CONS - FPUT (FIRST PUT)            ATOM - WORDP

          APPEND - LPUT (LAST PUT)           NULL - EMPTYP

          LIST - LIST                        NUMBERP - NUMBERP

          NCONC - N/A (NCONC IN EXPERLOGO)   SYMBOLP - N/A

          RPLACA - N/A (RPLACA IN EXPERLOGO) LISTP - LISTP

          RPLACD - N/A (RPLACD IN EXPERLOGO) EQUAL - EQUALP

          NREVERSE - N/A                     MEMBER - MEMBERP

          ASSOC - N/A (FINDKEY IN EXPERLOGO) GREATERP - GREATERP

          LENGTH - COUNT                     LESSP - LESSP

          REVERSE - N/A(REVERSE IN EXPERLOGO)ZEROP - N/A

          SUBST - N/A (SUBST IN EXPERLOGO)   MINUSP - N/A

          LCONC - N/A                        PLUSP - N/A

          TCONC - N/A                        EVENP - N/A

          SETQ - MAKE                        ODDP - N/A

          SETF - N/A                         COND - IF

          SET - N/A                          IF - IF

          DEFUN - TO

This is not an exhaustive list; several of the more  compli-cated 
or lesser-used LISP  functions  have  been  left  out.  The 
reader should see from this list,  though,  just how much of LISP 
has been implemented in Logo.



Sidebar 2
Writing LISP Functions in Logo

Many of the LISP primitives  and  predicates  that  are  not 
duplicated  in  Logo  can  be written in Logo.  Logo's power as a 
symbolic computation language allows the programmer to do this.

For example,  in LISP there is a powerful  primitive  called 
ASSOC. ASSOC looks for a key that is part of an association list. 
For example, if we set up the following association:

                    (SETQ 'JANE '((OCCUPATION STUDENT)
                                 (MAJOR COMPUTER-SCIENCE)
                                 (LANGUAGE LISP)))


ASSOC can retrieve the information we have set up.

Writing in LISP: (ASSOC 'LANGUAGE SALLY),  the computer will 
respond: (LANGUAGE LISP).

ASSOC is not defined in Logo. It is,  however,  very easy to 
create.  We  set  up  the  association  by  writing:  MAKE "SALLY 
[[OCCUPATION STUDENT] [MAJOR COMPUTER.SCIENCE] [LANGUAGE  LISP]]. 
We define the ASSOC primitive as follows:

                    TO ASSOC :KEY :OBJECT
                    IF EMPTYP :OBJECT [OUTPUT "? STOP]
                    IF  EQUALP  FIRST  FIRST  :OBJECT  :KEY  [OUTPUT  FIRST
          :OBJECT STOP]
                    OUTPUT ASSOC :KEY BF :OBJECT
                    END

Our Logo ASSOC goes through the  association  list    recur-
sively,  checking  each  key  to  see  if it matches the argument 
given.  If there is nothing in the association  list,  or  if  it 
cannot  find a match,  ASSOC will output a question mark.  When a 
match is found, the key and the object are output and the  proce-
dure stops.

ASSOC is a fairly complicated example.  Several of the  LISP 
primitives  that  do  not have Logo equivalents can be defined in 
one or two lines of Logo code.  For example,  to define the  Logo 
version of LISP's ZEROP, we write:

                    TO MY-ZEROP: NUMBER
                    IF EQUALP :NUMBER "0 [OUTPUT "TRUE]
                    IF  EQUALP  LAST  :NUMBER  "0  [OUTPUT  "TRUE]  [OUTPUT
          "FALSE]
                    END

The extensibility of Logo is helpful in the study  of  LISP. the  
student  trying to model LISP expressions in Logo will often need 
to write LISP primitives and predicates in Logo in order  to use 
them. I found in my own study that writing a LISP function in 
Logo gave me a deeper understanding of that function.  It takes a 
higher magnitude of understanding to write  a  function  than  it 
does just to use the function.



Sidebar 3
ExperLogo - A LISP-like Logo

One  version of Logo stands out from the others as being the most 
LISP-like in its form and structure - ExperLogo from  Exper-
Telligence.  ExperLogo's LISPness is apparent in  several    dif-
ferent  areas - from its rules of evaluation to its toolchest  of 
primitives and predicates.

The first noticeable LISP-like feature of ExperLogo  is  the way  
it evaluates its expressions.  In ExperLogo every expression is 
evaluated,  meaning that primitives and predicates will  print 
the  results  of  their evaluation on the screen without the need 
for a PRINT command.  This element of first-classness is an   im-
portant  feature  of  LISP  that is not found in most versions of 
Logo.

For example,  in most Logos to print the value of a variable the  
variable  has  to be combined with a PRINT command,  such as 
PRINT :PEOPLE.  In ExperLogo only the variable has to be written, 
as  in  :PEOPLE,  which  is much like the way it would be done in 
LISP - (PEOPLE).

ExperLogo is also more LISP-like in the way values are bound to 
variables.  In most Logos a value is bound to  a  variable  by 
writing  MAKE  "NAME "TOM.  In ExperLogo you can write: MAKE NAME 
TOM. In LISP it would be (SETQ NAME TOM).

Expressions that evaluate to  true  or  false  in  ExperLogo 
return values in the same manner as LISP,  either T or NIL, which 
is unlike most Logos, which return TRUE or FALSE.

Another area of ExperLogo that makes  it  so  comparable  to LISP 
is its expanded list of LISP-like primitives and predicates. In  
most  versions  of  Logo  there is not a primitive similar to 
LISP's REVERSE,  which takes the elements of a list  and  reverse 
their order. ExperLogo has REVERSE.

In LISP the primitive SUBST is used to substitute a new  ex-
pression  for an old expression in some target expression,  say a 
list.  Most versions of Logo do not have this powerful primitive; 
ExperLogo does.

A  very  powerful  primitive  in LISP is ASSOC (discussed in 
another sidebar).  Most Logos do not have this primitive,  though 
it  can  be  written in Logo.  ExperLogo has this primitive under 
another name - FINDKEY. FINDKEY works just like ASSOC; it takes a 
key word (atom) and an expression as arguments and then finds the 
element that goes with the key.

Here is a list of functions in ExperLogo which are not found in 
other Logos but can be found in LISP: ELEMS,  FINDKEY,  NCONC, 
NPUT,  PAIRLIST,  REMOVE,  REVERSE, RPLACA, RPLACD, SORT, SORTKEY 
and SUBST.  Some of these functions do not duplicate  their  LISP 
equivalent's  name,  but in following the Logo tradition are more 
mnemonic, hence easier to remember and understand.

ExperLogo at this time is available only for the  Macintosh, but  
if  you  have  a  Mac and are looking for a Logo with a high 
degree of LISP similarity,  I would highly recommend  looking  at 
this excellent Logo implementation.
SHAR_EOF
if test 7528 -ne "`wc -c < 'logo.mar'`"
then
	echo shar: "error transmitting 'logo.mar'" '(should have been 7528 characters)'
fi
fi
exit 0
#	End of shell archive
-- 
---------------
C'est la vie, C'est la guerre, C'est la pomme de terre
Mail:	Imagen Corp. 2650 San Tomas Expressway Santa Clara, CA 95052-8101 
UUCP:	...{decvax,ucbvax}!decwrl!imagen!turner      AT&T: (408) 986-9400