cl-scopes/csys/csys.lisp

119 lines
3.7 KiB
Common Lisp

;;;; cl-scopes/csys - concurrent cybernetic communication systems
(defpackage :scopes/csys
(:use :common-lisp)
(:local-nicknames (:actor :scopes/core/actor)
(:config :scopes/config)
(:message :scopes/core/message)
(:shape :scopes/shape)
(:util :scopes/util)
(:alx :alexandria))
(:export #:scope #:environ
#:make-program
#:neuron #:std-proc #:create-zero
#:handle-action
#:no-op
#:notify))
(in-package :scopes/csys)
;;;; scope: information a neuron has access to
(defclass scope ()
((value :accessor value :initarg :value :initform 0)
(categ :accessor categ :initarg :categ :initform '(:csys :c00))
(stage :accessor stage :initarg :stage :initform :initial)
(proc :accessor proc)
(program :reader program :initarg :program)
(syns :accessor syns :initform nil)
(environ :reader environ :initarg :environ)))
(defun scope (prg env &rest args &key (cls 'scope) &allow-other-keys)
(setf args (alx:remove-from-plist args :cls :environ :program))
(apply #'make-instance cls :program prg :environ env args))
(defmethod initialize-instance :after ((sc scope) &key &allow-other-keys)
(set-proc sc))
(defun reset-scope (scp &rest args)
(apply #'scope
(getf args :program (program scp))
(getf args :environ (environ scp))
:categ (getf args :categ (categ scp))
args))
(defun set-proc (scope)
(setf (proc scope) (funcall (program scope) scope))
scope)
(defgeneric make-program (spec)
(:method ((fn function)) (lambda (scp) fn)))
(defun create-zero (prg env &key (categ '(:csys :c00)) (name "0-0"))
(let* ((domain (car categ))
(addr (list domain (cadr categ) name))
(msg (message:create (list domain :create) :data (list :addr addr)))
(scope (scope prg env :categ categ)))
(create msg scope)))
;;;; neurons (= async tasks) and synapses (= connections)
(defun neuron (scope)
(actor:create (process scope)))
(defun update (scope)
(actor:become (process scope)))
(defun synapse (rcvr &optional (op #'identity))
(lambda (msg)
(actor:send rcvr (funcall op msg))))
;;;; message handlers, proc steps
(defun process (scope)
(lambda (msg) (funcall (proc scope) msg scope)))
(defun std-proc (msg scope &key (default #'remember) params actions)
(util:mv-bind (nmsg &optional (nscope scope))
(handle-action msg scope :default default :actions actions :params params)
(forward nmsg (syns nscope))
(update nscope)))
(defun eff-proc (msg scope &key params actions)
(util:mv-bind (nmsg &optional (nscope scope))
(handle-action msg scope :default #'no-op :actions actions :params params)
(notify nmsg nscope)
(update nscope)))
(defun create (msg scope)
(let ((new (neuron (apply #'reset-scope scope (shape:data msg)))))
(notify-created msg new scope)))
(defun do-log (msg scope)
(util:lgi msg))
(defun notify (msg scope)
(actor:send (environ scope) msg))
(defun forward (msg syns)
(dolist (s syns)
(funcall s msg)))
(defun handle-action (msg scope &key (default #'no-op) actions params)
(let* ((key (message:action msg))
(act (getf actions key (getf actions :default default))))
(apply act msg scope params)))
(defun notify-created (msg new scope)
(let* ((head (list (message:domain msg) :created))
(data (util:plist-merge (shape:data msg) `(:new ,new :parent ,actor:*self*)))
(msg1 (message:create head :data data)))
(notify msg1 scope)))
;;;; predefined neuron actions
(defun no-op (msg scope) msg)
(defun remember (msg scope)
(setf (value scope) (shape:data-value msg :value))
(values msg scope))