Реализация конечного автомата с использованием ключевого слова "доходность"

Можно ли использовать ключевое слово yield для реализации простой конечной машины как показано здесь. Для меня это похоже на то, что компилятор С# сделал для вас тяжелую работу, поскольку он внутренне реализует конечный автомат, чтобы заставить оператор yield работать.

Можете ли вы поработать над работой, которую уже выполняет компилятор, и заставить ее реализовать большую часть конечного автомата для вас?

Кто-нибудь это сделал, технически ли это возможно?

Ответ 1

Это возможно, но это плохая идея. Блоки Iterator были созданы, чтобы помочь вам создавать пользовательские итераторы для коллекций, а не для решения универсальной проблемы реализации государственных машин.

Если вы хотите записать конечный автомат, просто напишите конечный автомат. Это не сложно. Если вы хотите написать много государственных машин, напишите библиотеку полезных вспомогательных методов, которые позволят вам чисто представлять государственные машины, а затем использовать вашу библиотеку. Но не злоупотребляйте конструкцией языка, предназначенной для чего-то совершенно другого, который просто используется для использования государственных машин в качестве детали реализации. Это затрудняет чтение, понимание, отладку, поддержку и расширение вашего кода в государственном компьютере.

(И, кстати, я сделал двойной прием при чтении вашего имени. Один из дизайнеров С# также назван Matt Warren!)

Ответ 2

Да, это абсолютно возможно и легко сделать. Вы можете пользоваться конструкциями потока управления (for, foreach, while,... goto (используя goto, особенно подходит для этого сценария;))) вместе с yield, чтобы построить один.

IEnumerator<State> StateMachine
             (Func<int> currentInput /* gets current input from IO port */, 
              Func<int> currentOutput) {
    for (;;)  {
       if ((currentInput() & 1) == 0) 
           yield return new State("Ready"); 
       else {
           if (...) {
               yield return new State("Expecting more data");
               SendOutput(currentOutput());
               while ((currentInput() & 2) != 0) // while device busy
                    yield return new State("Busy");
           else if (...) { ... } 
       }
    }
}

// consumer:
int data;
var fsm = StateMachine(ReadFromIOPort, () => data);
// ...
while (fsm.Current != "Expecting more data")
    fsm.MoveNext();
data = 100;
fsm.MoveNext();

Ответ 3

В то время как это не является государственным автоматом в классическом смысле, статья о Iterator-based Micro Threading использует выход творчески для государственных действия.

IEnumerable Patrol ()
{
    while (alive){
        if (CanSeeTarget ()) {
            yield return Attack ();
        } else if (InReloadStation){
            Signal signal = AnimateReload ();
            yield return signal;
        } else {
            MoveTowardsNextWayPoint ();
            yield return TimeSpan.FromSeconds (1);
        };
    }
    yield break;
}

Ответ 4

Блоки Iterator действительно реализуют государственные машины, но сложный бит получает следующий вход. Как вы узнаете, куда двигаться дальше? Я предполагаю, что у вас может быть какая-то общая переменная "текущий переход", но это несколько нехорошее.

Если вам не нужен какой-либо вход (например, ваш конечный автомат только циклически перемещается между состояниями), тогда это легко, но это не интересный вид:)

Можете ли вы описать интересующий вас государственный автомат?