From: Kenny Tilton
Subject: Semaphor Examples 1 & 2
Date: 
Message-ID: <39E8FAE9.61EB4D85@nyc.rr.com>
;; -*- mode: Lisp; Syntax: Common-Lisp; Package: model; -*-
;;_________________________________________________________
;;
;;
;;          B o i l e r m a k e r
;;
;;   Copyright � 2000 by Kenny Tilton
;;

(in-package :model)

#|          Intro to Semaphors, Chapter 1

It occurred to me that the rah-rah stuff will be more comprehensible
after one has actually seen what I am talking about, so here are two
simple examples, rah-rah to follow.

|#



(defmodel boiler ()
  ((status :semaphor t :initarg :status :accessor status :initform
nil);; vanilla semaphor
   (temp :semaphor t :initarg :temp :accessor temp :initform nil)
   (vent :semaphor t :initarg :vent :accessor vent :initform nil)
   ))

(defun example-1 ()
  (md-reset) ;; resets debugging/testing specials
  (let ((b (make-instance 'boiler
             :temp (smv 20)
             :status (sm? (if (< (^temp self) 100) ;; #1 (footnote)
                              :on
                            :off))
             :vent (sm? (ecase (^status) ;; #2
                        (:on :open)
                        (:off :closed))))))

    (trc "boiler> temp:" (temp b) :status= (status b) :vent= (vent b))
;; #3

    (setf (temp b) 100) ;; recalculation of 'status then 'vent all
occurs during this 'setf

    (trc "boiler> temp:" (temp b) :status= (status b) :vent= (vent b))

    ))

#|

Output:

0> boiler> temp: 20 :STATUS= :ON
0> boiler> temp: 100 :STATUS= :OFF

Note 1: The 'sm? macro is used to define semaphoric formulas. ^temp is
a macro generated by the 'defmodel of boiler. ^macros work in concert
with
'sm? almost transparently to establish a dependency (almost--just don't
forget
the ^, which for some reason I almost never do).

Note 2: The ^macros single parameter is optional and defaults to 'self
for convenience.

Note 3: 'trc prints to the debugger window. Notice an almost incidental
charm of
Semaphors, viz, initialization of a slot based on calculations against
other slots. Sometimes these days I make a slot semaphoric simply to get
that
capability.

Now let's see how echo functions can be used...

|#

(def-sm-echo (status) () ;; parameters default to (self newValue
oldValue)
  (trc "boiler" self :oldstatus= oldValue :newstatus= newValue)
  ;
  ; also call boiler API to actually turn it on or off
  ;
  )

(def-sm-echo (vent) ()
  (trc "boiler vent changing from" oldValue :to newValue)
  ;
  ; also call boiler API to actually open or close it
  ;
  )

;
; And let's also demonstrate inter-object dependency by
; separating out the thermometer
;

(defmodel boiler2 ()
  ((status :semaphor t :initarg :status :accessor status :initform
nil);; vanilla semaphor
   (vent :semaphor t :initarg :vent :accessor vent :initform nil)
   (thermometer :initarg :thermometer :accessor thermometer :initform
nil)
   ))

;-------------------------

(defmodel thermometer ()
  ((temp :semaphor t :initarg :temp :accessor temp :initform nil)
   ))

(def-sm-echo (temp) ((self Thermometer) newTemp oldTemp)
  (trc "thermometer temp changing from" oldTemp :to newTemp))

;--------------------------

(defun example-2 ()
  (md-reset) ;; resets debugging/testing specials

  (let ((b (make-instance 'Boiler2
              :status (sm? (if (< (^temp (Thermometer self)) 100)
                               :on :off))
              :vent (sm? (ecase (^status)
                           (:on :open)
                           (:off :closed)))
              :thermometer (make-instance 'Thermometer
                             :temp (smv 20))))
         )


    (trc "------to 100---------")

    (setf (temp (Thermometer b)) 100)

    (trc "------to 101---------")

    (setf (temp (Thermometer b)) 101)

    (trc "------to 101---------")

    (setf (temp (Thermometer b)) 101)

    ))

#|

Output:

0> thermometer temp changing from NIL :TO 20
0> boiler <BOILER2 BOILER2> :OLDSTATUS= NIL :NEWSTATUS= :ON
0> boiler vent changing from NIL :TO :OPEN
0> ------to 100---------
0> thermometer temp changing from 20 :TO 100
0> boiler <BOILER2 BOILER2> :OLDSTATUS= :ON :NEWSTATUS= :OFF
0> boiler vent changing from :OPEN :TO :CLOSED
0> ------to 101---------
0> thermometer temp changing from 100 :TO 101
0> ------to 101---------


|#