HiveBrain v1.2.0
Get Started
← Back to all entries
patternMinor

Finite State Machine code

Submitted by: @import:stackexchange-codereview··
0
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.

``
;;; 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 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.