Конечного автомата код


Я делал сегодня это ФСМ. Однако, как это, наверное, самая большая практическая программа, которую я когда-либо написал в ЦЗ, я не знаю, если есть некоторые вещи, которые можно улучшить, или если вы используете закрытие-это лучшее, что здесь.

Любая обратная связь приветствуется.

;;; 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 rested 0))
         (defun controller ()
             (dotimes (n 30)
                 (cond ((equal state 'QuenchThirst) (QuenchThirst))
                             ((equal state 'VisitBankAndDepositGold) (VisitBankAndDepositGold))
                             ((equal state 'GoHomeAndSleepTillRested) (GoHomeAndSleepTillRested))
                             ((equal state 'EnterMineAndDigForNugget) (EnterMineAndDigForNugget))))))))

Редактировать

Я применил все предложенные изменения, но на флэт/метки один. Все работало нормально, пока я не изменил один из "установить состояние к следующей функции". Теперь, макрос, введите не называл.

Это текущее состояние кода, с необходимый код, чтобы заставить его работать

;;; States: -- enter-mine-and-dig-for-nugget 
;;;         -- quench-thirst
;;;         -- go-home-and-sleep-till-rested
;;;         -- visit-bank-and-deposit-gold


(defmacro enter (state)
    `(setf state ,state))

(defun make-miner ()
    (let ((wealth 0)
                (thirst 0)
                (rested 0)
                (state #'enter-mine-and-dig-for-nugget))
        (list 
         (defun enter-mine-and-dig-for-nugget ()
             (format t "~&Diggin' up gold!")
             (incf wealth)
             (incf thirst)
             (if (>= thirst 7)
                     (enter #'quench-thirst)
                 (enter #'visit-bank-and-deposit-gold)))
     (defun quench-thirst () 
         (format t "~&Drinkin' old good whiskey")
         (setf thirst 0)
         (enter #'enter-mine-and-dig-for-nugget))
     (defun visit-bank-and-deposit-gold ()
         (format t "~&All this gold ought to be stored somewhere!")
         (incf wealth)
         (if (>= wealth 5)
                 (progn 
                     (format t "~&Too much gold for today, let's sleep!")
                     (enter #'go-home-and-sleep-till-rested)
                     (setf wealth 0))
                 (enter #'enter-mine-and-dig-for-nugget)))
     (defun go-home-and-sleep-till-rested ()
         (dotimes (i 4)
             (format t "~&Sleepin'"))
         (enter #'enter-mine-and-dig-for-nugget))
     (defun controller ()
         (dotimes (n 30)
             (funcall state))))))

(let ((a (make-miner)))
    (funcall (fifth a)))


3089
5
задан 3 сентября 2011 в 12:09 Источник Поделиться
Комментарии
4 ответа

Сайт defun

Самая основная ошибка в вашем коде заключается в том, что сайт defun не правильно вложенных функций. Сайт defun - это топ-уровень макросов, определяющие функции верхнего уровня и должны быть использованы в верхнего уровня формы.

Вложенные функции определены в общих сюсюкаться с флэт и этикетки. Метки используется для рекурсивной подпрограммы-функции.

Именования

Такие символы, как FooBarBaz не используют в общий Лисп. По умолчанию общий Лисп upcases все имена внутренне, поэтому случае информация теряется.

Обычно мы пишем фу-бар-баз.

Проверка символов

Использовать чехол (или ECASE) вместо (Конд ((равными фу 'бар) ...)).

Архитектура

Обычно я бы написал, что кусок кода, используя Кло, общей системы объекта сюсюкать.

В более функциональном стиле, я бы предложил следующее:


  • используйте ярлыки для местных процедур.

  • установить состояние к следующей функции. Функция записывается как (моя функция-функция) или #'мои функции.

  • контроллер просто вызывает следующую функцию от переменной состояния. Не надо перечислять все случаи.

4
ответ дан 4 сентября 2011 в 12:09 Источник Поделиться

Вы можете прокомментировать то, что цель/выходных данных этой программы должна быть? Как ты должен использовать его? Похоже, что сделать-Шахтер просто возвращает список функций, которые не полезны по-своему.

Некоторые предварительные замечания:


Вы можете сократить время макроса. КЛ предоставляет вам множество итерационных конструкций (делать, dotimes, долист, mapcar и друзей, и петля). Это может делать то, что вы хотите здесь (и много больше, если вы чувствуете, как чтение);

(loop while (<= rested 3)
do (format t "~&Sleepin'")
do (incf rested))

С момента сброса отдыхал в 0 позже в этом же блоке в любом случае, вы могли бы также просто сделать

(loop repeat 4 do (format t "~&Sleepin'"))

или

(dotimes (i 4) do (format t "~&Sleepin'"))


Общий Лисп Конвенции заключается в использовании накатал-строчными-имена , а не CamelCaseNames.


Конд положения не требуется явное progn, но читать на первой


Там, где ты (усл ([тест] [п.]) (т [п.])), Вы можете вместо этого написать (если [тест] [пункт] [пункт]). Например,

(if (>= wealth 5) 
(progn
(format t "~&Too much gold for today, let's sleep!")
(enter 'GoHomeAndSleepTillRested)
(setf wealth 0))
(EnterMineAndDigForNugget))

Вы на самом деле нужны progn здесь. В общем, вы должны использовать Конд , где вы бы обычно использовать если/ключевые слова elseif/еще в других языках (случай на самом деле переключатель аналог), и использовать если/когда/если там, где вы можете получить сигнал намерениях.

3
ответ дан 3 сентября 2011 в 02:09 Источник Поделиться

В качестве второго редактирования.

Ок, да теперь, когда вы показали, как это должно называться, Кло-определенно способ пойти сюда. Представляя объект как список замыканий является менее оптимальным, если для никакой другой причины, что нужно прибегнуть к (funcall (пятый-Шахтер)) для того, чтобы на самом деле запустить его (а следовательно, изменить что звонок каждый раз, когда вы добавляете новый "способ" на свой Шахтер). Есть еще проблема, что каждый "шахтер" вы тиражируете таскает свой независимый функции (так что удачи изменять поведение во время выполнения или использования какой-либо наследство для более сложного моделирования).

Я предлагаю вам взглянуть на этот Кло учебник , а также главы 16 и 17 из практических общий Лисп

Вот транслитерацию вашей программы, используя Кло в качестве учебного пособия:

(defpackage :cl-miner (:use :cl))
(in-package :cl-miner)

(defclass miner ()
((wealth :accessor wealth :initarg :wealth :initform 0)
(thirst :accessor thirst :initarg :thirst :initform 0)
(rested :accessor rested :initarg :rested :initform 0)
(state :accessor state :initarg :state :initform #'enter-mine-and-dig-for-nugget)))

;;;;;;;;;;;;;;; shortcuts
(defmethod enter ((m miner) a-state)
(setf (state m) a-state))

(defun make-miner ()
(make-instance 'miner))

;;;;;;;;;;;;;;; miner methods
(defmethod enter-mine-and-dig-for-nugget ((m miner))
(format t "~&Diggin' up gold!")
(incf (wealth m))
(incf (thirst m))
(if (>= (thirst m) 7)
(enter m #'quench-thirst)
(enter m #'visit-bank-and-deposit-gold)))

(defmethod quench-thirst ((m miner))
(format t "~&Drinkin' old good whiskey")
(setf (thirst m) 0)
(enter m #'enter-mine-and-dig-for-nugget))

(defmethod visit-bank-and-deposit-gold ((m miner))
(format t "~&All this gold ought to be stored somewhere!")
(incf (wealth m))
(if (>= (wealth m) 5)
(progn
(format t "~&Too much gold for today, let's sleep!")
(enter m #'go-home-and-sleep-till-rested)
(setf (wealth m) 0))
(enter m #'enter-mine-and-dig-for-nugget)))

(defmethod go-home-and-sleep-till-rested ((m miner))
(dotimes (i 4)
(format t "~&Sleepin'"))
(enter m #'enter-mine-and-dig-for-nugget))

(defmethod work ((m miner))
(dotimes (n 30)
(funcall (state m) m)))

(let ((a (make-miner)))
(work a))

Я собирался сравнить их по производительности, но я не мог получить свой пересмотренный вариант запустить (он дал мне "необработанное ошибка" ошибка чего я не видел раньше).

3
ответ дан 13 сентября 2011 в 04:09 Источник Поделиться

Если ваши ФСМ вряд ли когда-нибудь изменения, и производительность является вашей основной задачей, вы не можете разбить это.

Перевести его в простой структурированный код, в progn или любой другой, который вы можете сделать с любым ФСМ.
Вот "с-иш" эквивалент:

w = th = 0;
while(T){
w++; th++;
// Diggin' up gold!
if (th >= 7){
// Drinkin' old good whiskey
th = 0;
} else {
// all this gold ought to be stored somewhere
if (w >= 5){
// Too much gold for today, let's sleep!
w = 0;
for (r = 0; r <= 3; r++){
// sleepin'
}
}
}
}

0
ответ дан 14 сентября 2011 в 11:09 Источник Поделиться