patternMinor
Finite State Machine code
Viewed 0 times
machinecodefinitestate
Problem
I have been making this FSM today. However, as this is probably the biggest practical program I have ever written in CL, I don't know if there are some things that could be improved, or if using a closure is the best thing here.
Any feedback is appreciated.
``
((not ,test))
,@body))
(defmacro enter (state)
`(setf state ,state))
(defun make-miner ()
(let ((wealth 0)
(thirst 0)
(rested 0)
(state 'EnterMineAndDigForNugget))
(list
(defun EnterMineAndDigForNugget ()
; (setf location 'mine)
(format t "~&Diggin' up gold!")
(incf wealth)
(incf thirst)
(cond ((>= thirst 7) (enter 'QuenchThirst))
(t (enter 'VisitBankAndDepositGold))))
(defun QuenchThirst ()
(format t "~&Drinkin' old good whiskey")
(setf thirst 0)
(enter 'EnterMineAndDigForNugget))
(defun VisitBankAndDepositGold ()
(format t "~&All this gold ought to be stored somewhere!")
(incf wealth)
(cond ((>= wealth 5) (progn
(format t "~&Too much gold for today, let's sleep!")
(enter 'GoHomeAndSleepTillRested)
(setf wealth 0)))
(t (EnterMineAndDigForNugget))))
(defun GoHomeAndSleepTillRested ()
(while (<= rested 3)
(format t "~&Sleepin'")
(incf rested))
(enter 'EnterMineAndDigForNugget)
(setf rest
Any feedback is appreciated.
``
;;; States: -- EnterMineAndDigForNugget
;;; -- QuenchThirst
;;; -- GoHomeAndSleepTillRested
;;; -- VisitBankAndDepositGold
(defmacro while (test &rest body)
(do ()((not ,test))
,@body))
(defmacro enter (state)
`(setf state ,state))
(defun make-miner ()
(let ((wealth 0)
(thirst 0)
(rested 0)
(state 'EnterMineAndDigForNugget))
(list
(defun EnterMineAndDigForNugget ()
; (setf location 'mine)
(format t "~&Diggin' up gold!")
(incf wealth)
(incf thirst)
(cond ((>= thirst 7) (enter 'QuenchThirst))
(t (enter 'VisitBankAndDepositGold))))
(defun QuenchThirst ()
(format t "~&Drinkin' old good whiskey")
(setf thirst 0)
(enter 'EnterMineAndDigForNugget))
(defun VisitBankAndDepositGold ()
(format t "~&All this gold ought to be stored somewhere!")
(incf wealth)
(cond ((>= wealth 5) (progn
(format t "~&Too much gold for today, let's sleep!")
(enter 'GoHomeAndSleepTillRested)
(setf wealth 0)))
(t (EnterMineAndDigForNugget))))
(defun GoHomeAndSleepTillRested ()
(while (<= rested 3)
(format t "~&Sleepin'")
(incf rested))
(enter 'EnterMineAndDigForNugget)
(setf rest
Solution
DEFUN
The most basic mistake in your code is that
Nested functions are defined in Common Lisp with
Naming
Symbols like
Usually we write
Checking symbols
Use
Architecture
Usually I would write that piece of code using CLOS, the Common Lisp Object System.
In a more functional style I would propose the following:
-
use
-
set the state to the next function. A function is written as
-
the controller just calls the next function from the state variable. It is not necessary to list all cases.
The most basic mistake in your code is that
DEFUN is not correct for nested functions. DEFUN is a top-level macro, defining a top-level function and should be used in top-level forms.Nested functions are defined in Common Lisp with
FLET and LABELS. LABELS is used for recursive sub-functions.Naming
Symbols like
FooBarBaz are not use in Common Lisp. By default Common Lisp upcases all names internally, so the case information gets lost.Usually we write
foo-bar-baz.Checking symbols
Use
CASE (or ECASE) instead of (cond ((equal foo 'bar) ...)).Architecture
Usually I would write that piece of code using CLOS, the Common Lisp Object System.
In a more functional style I would propose the following:
-
use
LABELS for the local procedures.-
set the state to the next function. A function is written as
(function my-function) or #'my-function.-
the controller just calls the next function from the state variable. It is not necessary to list all cases.
Context
StackExchange Code Review Q#4557, answer score: 5
Revisions (0)
No revisions yet.