用于状态机

发布于 2024-07-08 10:03:25 字数 93 浏览 10 评论 0原文

我会在哪些编程领域使用状态机? 为什么 ? 我怎样才能实现一个?

编辑:如果要求不过分,请提供一个实际的例子。

In what areas of programming would I use state machines ? Why ? How could I implement one ?

EDIT: please provide a practical example , if it's not too much to ask .

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(18

若水般的淡然安静女子 2024-07-15 10:03:25

我会在哪些编程领域使用状态机?

使用状态机来表示一个(真实的或逻辑的)对象,该对象可以存在于有限数量的条件(“状态”)中,并根据一组固定的规则从一个状态进展到下一个状态。

为什么要使用状态机?

状态机通常是一种非常紧凑的方式来表示一组复杂的规则和条件,并处理各种输入。 您将在内存有限的嵌入式设备中看到状态机。 如果实施得当,状态机是自记录的,因为每个逻辑状态都代表一种物理条件。 与程序等价物相比,状态机可以用极少的代码来实现,并且运行效率极高。 此外,管理状态变化的规则通常可以作为数据存储在表中,提供易于维护的紧凑表示。

我该如何实施?

简单的例子:

enum states {      // Define the states in the state machine.
  NO_PIZZA,        // Exit state machine.
  COUNT_PEOPLE,    // Ask user for # of people.
  COUNT_SLICES,    // Ask user for # slices.
  SERVE_PIZZA,     // Validate and serve.
  EAT_PIZZA        // Task is complete.
} STATE;

STATE state = COUNT_PEOPLE;
int nPeople, nSlices, nSlicesPerPerson;

// Serve slices of pizza to people, so that each person gets
/// the same number of slices.   
while (state != NO_PIZZA)  {
   switch (state)  {
   case COUNT_PEOPLE:  
       if (promptForPeople(&nPeople))  // If input is valid..
           state = COUNT_SLICES;       // .. go to next state..
       break;                          // .. else remain in this state.
   case COUNT_SLICES:  
       if (promptForSlices(&nSlices))
          state = SERVE_PIZZA;
        break;
   case SERVE_PIZZA:
       if (nSlices % nPeople != 0)    // Can't divide the pizza evenly.
       {                             
           getMorePizzaOrFriends();   // Do something about it.
           state = COUNT_PEOPLE;      // Start over.
       }
       else
       {
           nSlicesPerPerson = nSlices/nPeople;
           state = EAT_PIZZA;
       }
       break;
   case EAT_PIZZA:
       // etc...
       state = NO_PIZZA;  // Exit the state machine.
       break;
   } // switch
} // while

注释:

  • 为简单起见,该示例使用具有显式 case/break 状态的 switch()。 实际上,case 通常会“失败”到下一个状态。

  • 为了便于维护大型状态机,每个case中完成的工作可以封装在“worker”函数中。 while()顶部的任何输入,将其传递给辅助函数,并检查辅助函数的返回值以计算下一个状态。

  • 为了紧凑,整个 switch() 可以用函数指针数组替换。 每个状态都由一个函数体现,该函数的返回值是指向下一个状态的指针。 警告:这会简化状态机或使其完全不可维护,因此请仔细考虑实现!

  • 嵌入式设备可以实现为仅在发生灾难性错误时退出的状态机,之后执行硬重置并重新进入状态机。

In what areas of programming would I use a state machine?

Use a state machine to represent a (real or logical) object that can exist in a limited number of conditions ("states") and progresses from one state to the next according to a fixed set of rules.

Why would I use a state machine?

A state machine is often a very compact way to represent a set of complex rules and conditions, and to process various inputs. You'll see state machines in embedded devices that have limited memory. Implemented well, a state machine is self-documenting because each logical state represents a physical condition. A state machine can be embodied in a tiny amount of code in comparison to its procedural equivalent and runs extremely efficiently. Moreover, the rules that govern state changes can often be stored as data in a table, providing a compact representation that can be easily maintained.

How can I implement one?

Trivial example:

enum states {      // Define the states in the state machine.
  NO_PIZZA,        // Exit state machine.
  COUNT_PEOPLE,    // Ask user for # of people.
  COUNT_SLICES,    // Ask user for # slices.
  SERVE_PIZZA,     // Validate and serve.
  EAT_PIZZA        // Task is complete.
} STATE;

STATE state = COUNT_PEOPLE;
int nPeople, nSlices, nSlicesPerPerson;

// Serve slices of pizza to people, so that each person gets
/// the same number of slices.   
while (state != NO_PIZZA)  {
   switch (state)  {
   case COUNT_PEOPLE:  
       if (promptForPeople(&nPeople))  // If input is valid..
           state = COUNT_SLICES;       // .. go to next state..
       break;                          // .. else remain in this state.
   case COUNT_SLICES:  
       if (promptForSlices(&nSlices))
          state = SERVE_PIZZA;
        break;
   case SERVE_PIZZA:
       if (nSlices % nPeople != 0)    // Can't divide the pizza evenly.
       {                             
           getMorePizzaOrFriends();   // Do something about it.
           state = COUNT_PEOPLE;      // Start over.
       }
       else
       {
           nSlicesPerPerson = nSlices/nPeople;
           state = EAT_PIZZA;
       }
       break;
   case EAT_PIZZA:
       // etc...
       state = NO_PIZZA;  // Exit the state machine.
       break;
   } // switch
} // while

Notes:

  • The example uses a switch() with explicit case/break states for simplicity. In practice, a case will often "fall through" to the next state.

  • For ease of maintaining a large state machine, the work done in each case can be encapsulated in a "worker" function. Get any input at the top of the while(), pass it to the worker function, and check the return value of the worker to compute the next state.

  • For compactness, the entire switch() can be replaced with an array of function pointers. Each state is embodied by a function whose return value is a pointer to the next state. Warning: This can either simplify the state machine or render it totally unmaintainable, so consider the implementation carefully!

  • An embedded device may be implemented as a state machine that exits only on a catastrophic error, after which it performs a hard reset and re-enters the state machine.

池木 2024-07-15 10:03:25

已经有一些很好的答案了。 对于稍微不同的观点,请考虑在较大的字符串中搜索文本。 有人已经提到了正则表达式,这实际上只是一种特殊情况,尽管很重要。

考虑以下方法调用:

very_long_text = "Bereshit bara Elohim et hashamayim ve'et ha'arets." …
word = "Elohim"
position = find_in_string(very_long_text, word)

您将如何实现find_in_string? 最简单的方法是使用嵌套循环,如下所示:

for i in 0 … length(very_long_text) - length(word):
    found = true
    for j in 0 … length(word):
        if (very_long_text[i] != word[j]):
            found = false
            break
    if found: return i
return -1

除了效率低之外,它还形成了一个状态机! 这里的状态有些隐藏; 让我稍微重写一下代码,使它们更明显:

state = 0
for i in 0 … length(very_long_text) - length(word):
    if very_long_text[i] == word[state]:
        state += 1
        if state == length(word) + 1: return i
    else:
        state = 0
return -1

这里的不同状态直接代表我们搜索的单词中的所有不同位置。 图中的每个节点有两个转换:如果字母匹配,则转到下一个状态;如果匹配,则转到下一个状态。 对于每个其他输入(即当前位置的每个其他字母),返回到零。

这种轻微的重新制定有一个巨大的优势:现在可以使用一些基本技术对其进行调整以产生更好的性能。 事实上,每个高级字符串搜索算法(暂时不考虑索引数据结构)都建立在这个状态机之上,并改进了它的某些方面。

Some great answers already. For a slightly different perspective, consider searching a text in a larger string. Someone has already mentioned regular expressions and this is really just a special case, albeit an important one.

Consider the following method call:

very_long_text = "Bereshit bara Elohim et hashamayim ve'et ha'arets." …
word = "Elohim"
position = find_in_string(very_long_text, word)

How would you implement find_in_string? The easy approach would use a nested loop, something like this:

for i in 0 … length(very_long_text) - length(word):
    found = true
    for j in 0 … length(word):
        if (very_long_text[i] != word[j]):
            found = false
            break
    if found: return i
return -1

Apart from the fact that this is inefficient, it forms a state machine! The states here are somewhat hidden; let me rewrite the code slightly to make them more visible:

state = 0
for i in 0 … length(very_long_text) - length(word):
    if very_long_text[i] == word[state]:
        state += 1
        if state == length(word) + 1: return i
    else:
        state = 0
return -1

The different states here directly represent all different positions in the word we search for. There are two transitions for each node in the graph: if the letters match, go to the next state; for every other input (i.e. every other letter at the current position), go back to zero.

This slight reformulation has a huge advantage: it can now be tweaked to yield better performance using some basic techniques. In fact, every advanced string searching algorithm (discounting index data structures for the moment) builds on top of this state machine and improves some aspects of it.

清风挽心 2024-07-15 10:03:25

什么类型的任务?

任何任务,但据我所知,任何类型的解析通常都是作为状态机实现的。

为什么?

解析语法通常不是一项简单的任务。 在设计阶段,绘制状态图来测试解析算法是相当常见的。 将其转换为状态机实现是一项相当简单的任务。

怎么做?

好吧,你只受你的想象力的限制。

我已经看到它是通过 case 语句和循环 完成的。

我已经看到它是用 标签和 goto 语句

我什至看到它是用代表当前状态的函数指针结构完成的。 当状态改变时,一个或多个函数指针被更新。

我只见过它在代码中完成,其中状态的更改仅意味着您正在不同的代码部分中运行。 (没有状态变量,必要时有冗余代码。这可以被演示为一种非常简单的排序,仅对非常小的数据集有用。

int a[10] = {some unsorted integers};

not_sorted_state:;
    z = -1;
    while (z < (sizeof(a) / sizeof(a[0]) - 1)
    {
        z = z + 1
        if (a[z] > a[z + 1])
        {
            // ASSERT The array is not in order
            swap(a[z], a[z + 1];        // make the array more sorted
            goto not_sorted_state;      // change state to sort the array
        }
    }
    // ASSERT the array is in order

没有状态变量,但代码本身代表状态

What sort of task?

Any task but from what I have seen, Parsing of any sort is frequently implemented as a state machine.

Why?

Parsing a grammar is generally not a straightforward task. During the design phase it is fairly common that a state diagram is drawn to test the parsing algorithm. Translating that to a state machine implementation is a fairly simple task.

How?

Well, you are limited only by your imagination.

I have seen it done with case statements and loops.

I have seen it done with labels and goto statements

I have even seen it done with structures of function pointers which represent the current state. When the state changes, one or more function pointer is updated.

I have seen it done in code only, where a change of state simply means that you are running in a different section of code. (no state variables, and redundent code where necessary. This can be demonstrated as a very simply sort, which is useful for only very small sets of data.

int a[10] = {some unsorted integers};

not_sorted_state:;
    z = -1;
    while (z < (sizeof(a) / sizeof(a[0]) - 1)
    {
        z = z + 1
        if (a[z] > a[z + 1])
        {
            // ASSERT The array is not in order
            swap(a[z], a[z + 1];        // make the array more sorted
            goto not_sorted_state;      // change state to sort the array
        }
    }
    // ASSERT the array is in order

There are no state variables, but the code itself represents the state

甜味拾荒者 2024-07-15 10:03:25

状态设计模式是一种面向对象的方式,通过有限状态机。 它通常有助于降低该对象实现的逻辑复杂性(嵌套 if、许多标志等)

The State design pattern is an object-oriented way to represent the state of an object by means of a finite state machine. It usually helps to reduce the logical complexity of that object's implementation (nested if's, many flags, etc.)

稀香 2024-07-15 10:03:25

大多数工作流程可以作为状态机来实现。 例如,处理休假申请或订单。

如果您使用 .NET,请尝试 Windows Workflow Foundation。 您可以使用它快速实现状态机工作流程。

Most workflows can be implemented as state machines. For example, processing leave applications or orders.

If you're using .NET, try Windows Workflow Foundation. You can implement a state machine workflow quite quickly with it.

九厘米的零° 2024-07-15 10:03:25

如果您使用 C#,那么每当您编写迭代器块时,您都会要求编译器为您构建一个状态机(跟踪您在迭代器中的位置等)。

If you're using C#, any time you write an iterator block you're asking the compiler to build a state machine for you (keeping track of where you are in the iterator etc).

寻找一个思念的角度 2024-07-15 10:03:25

这是状态机的经过测试和工作的示例。 假设您正在使用串行流(串行端口、tcp/ip 数据或文件是典型示例)。 在本例中,我正在寻找一种特定的数据包结构,该结构可以分为三个部分:同步、长度和有效负载。 我有三个状态,一个是空闲,等待同步,第二个是我们有一个良好的同步,下一个字节应该是长度,第三个状态是累积有效负载。

该示例是纯串行的,只有一个缓冲区,如此处所写,它将从坏字节或数据包中恢复,可能会丢弃数据包但最终恢复,您可以执行其他操作,例如滑动窗口以允许立即恢复。 这就是您所说的部分数据包被剪短然后开始新的完整数据包的地方,下面的代码不会检测到这一点,并将丢弃部分数据包和整个数据包并在下一个数据包中恢复。 如果您确实需要处理所有整个数据包,那么滑动窗口可以节省您的时间。

我一直使用这种状态机,无论是串行数据流、tcp/ip、文件 i/o。 或者也许是 tcp/ip 协议本身,假设您要发送电子邮件,打开端口,等待服务器发送响应,发送 HELO,等待服务器发送数据包,发送数据包,等待回复,本质上,在这种情况以及下面的情况下,您可能会空闲等待下一个字节/数据包的进入。要记住您在等待什么,还要重用等待您可以使用的内容的代码状态变量。 状态机在逻辑中的使用方式相同(等待下一个时钟,我在等什么)。

就像逻辑一样,您可能希望对每个状态执行不同的操作,在这种情况下,如果我有一个良好的同步模式,我会将偏移量重置到我的存储中,并重置校验和累加器。 数据包长度状态演示了您可能想要中止正常控制路径的情况。 并非全部,事实上许多状态机可能会在正常路径内跳转或循环,下面的状态机几乎是线性的。

我希望这是有用的,并希望状态机在软件中得到更多的使用。

测试数据故意存在问题,状态机可以从中恢复。 在第一个好数据包、校验和错误的数据包以及长度无效的数据包之后存在一些垃圾数据。 我的输出是:

好数据包:FA0712345678EB
无效同步模式 0x12
无效的同步模式 0x34
无效同步模式 0x56
校验和错误 0xBF
无效数据包长度 0
无效同步模式 0x12
无效的同步模式 0x34
无效同步模式 0x56
无效同步模式 0x78
无效同步模式 0xEB
好包:FA081234567800EA
没有更多的测试数据

尽管有坏数据,但仍提取了流中的两个好数据包。 并对不良数据进行检测和处理。

 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>

unsigned char testdata[] =
{
    0xFA,0x07,0x12,0x34,0x56,0x78,0xEB,  
    0x12,0x34,0x56,  
    0xFA,0x07,0x12,0x34,0x56,0x78,0xAA,  
    0xFA,0x00,0x12,0x34,0x56,0x78,0xEB,  
    0xFA,0x08,0x12,0x34,0x56,0x78,0x00,0xEA  
};

unsigned int testoff=0;

//packet structure  
// [0] packet header 0xFA  
// [1] bytes in packet (n)  
// [2] payload  
// ... payload  
// [n-1] checksum  
//  

unsigned int state;

unsigned int packlen;  
unsigned int packoff;  
unsigned char packet[256];  
unsigned int checksum;  

int process_packet( unsigned char *data, unsigned int len )  
{  
    unsigned int ra;  

    printf("good packet:");
    for(ra=0;ra<len;ra++) printf("%02X",data[ra]);
    printf("\n");
}  
int getbyte ( unsigned char *d )  
{  
    //check peripheral for a new byte  
    //or serialize a packet or file  

    if(testoff<sizeof(testdata))
    {
        *d=testdata[testoff++];
        return(1);
    }
    else
    {
        printf("no more test data\n");
        exit(0);
    }
    return(0);
}

int main ( void )  
{  
    unsigned char b;

    state=0; //idle

    while(1)
    {
        if(getbyte(&b))
        {
            switch(state)
            {
                case 0: //idle
                    if(b!=0xFA)
                    {
                        printf("Invalid sync pattern 0x%02X\n",b);
                        break;
                    }
                    packoff=0;
                    checksum=b;
                    packet[packoff++]=b;

                    state++;
                    break;
                case 1: //packet length
                    checksum+=b;
                    packet[packoff++]=b;

                    packlen=b;
                    if(packlen<3)
                    {
                        printf("Invalid packet length %u\n",packlen);
                        state=0;
                        break;
                    }

                    state++;
                    break;
                case 2: //payload
                    checksum+=b;
                    packet[packoff++]=b;

                    if(packoff>=packlen)
                    {
                        state=0;
                        checksum=checksum&0xFF;
                        if(checksum)
                        {
                            printf("Checksum error 0x%02X\n",checksum);
                        }
                        else
                        {
                            process_packet(packet,packlen);
                        }
                    }
                    break;
            }
        }

        //do other stuff, handle other devices/interfaces

    }
}

Here is a tested and working example of a state machine. Say you are on a serial stream (serial port, tcp/ip data, or file are typical examples). In this case I am looking for a specific packet structure that can be broken into three parts, sync, length, and payload. I have three states, one is idle, waiting for the sync, the second is we have a good sync the next byte should be length, and the third state is accumulate the payload.

The example is purely serial with only one buffer, as written here it will recover from a bad byte or packet, possibly discarding a packet but eventually recovering, you can do other things like a sliding window to allow for immediate recovery. This would be where you have say a partial packet that is cut short then a new complete packet starts, the code below wont detect this and will throw away the partial as well as the whole packet and recover on the next. A sliding window would save you there if you really needed to process all the whole packets.

I use this kind of a state machine all the time be it serial data streams, tcp/ip, file i/o. Or perhaps tcp/ip protocols themselves, say you want to send an email, open the port, wait for the server to send a response, send HELO, wait for the server to send a packet, send a packet, wait for the reply, etc. Essentially in that case as well as in the case below you may be idling waiting for that next byte/packet to come in. To remember what you were waiting for, also to re-use the code that waits for something you can use state variables. The same way that state machines are used in logic (waiting for the next clock, what was I waiting for).

Just like in logic, you may want to do something different for each state, in this case if I have a good sync pattern I reset the offset into my storage as well as reset the checksum accumulator. The packet length state demonstrates a case where you may want to abort out of the normal control path. Not all, in fact many state machines may jump around or may loop around within the normal path, the one below is pretty much linear.

I hope this is useful and wish that state machines were used more in software.

The test data has intentional problems with it that the state machine recovers from. There is some garbage data after the first good packet, a packet with a bad checksum, and a packet with an invalid length. My output was:

good packet:FA0712345678EB
Invalid sync pattern 0x12
Invalid sync pattern 0x34
Invalid sync pattern 0x56
Checksum error 0xBF
Invalid packet length 0
Invalid sync pattern 0x12
Invalid sync pattern 0x34
Invalid sync pattern 0x56
Invalid sync pattern 0x78
Invalid sync pattern 0xEB
good packet:FA081234567800EA
no more test data

The two good packets in the stream were extracted despite the bad data. And the bad data was detected and dealt with.

 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>

unsigned char testdata[] =
{
    0xFA,0x07,0x12,0x34,0x56,0x78,0xEB,  
    0x12,0x34,0x56,  
    0xFA,0x07,0x12,0x34,0x56,0x78,0xAA,  
    0xFA,0x00,0x12,0x34,0x56,0x78,0xEB,  
    0xFA,0x08,0x12,0x34,0x56,0x78,0x00,0xEA  
};

unsigned int testoff=0;

//packet structure  
// [0] packet header 0xFA  
// [1] bytes in packet (n)  
// [2] payload  
// ... payload  
// [n-1] checksum  
//  

unsigned int state;

unsigned int packlen;  
unsigned int packoff;  
unsigned char packet[256];  
unsigned int checksum;  

int process_packet( unsigned char *data, unsigned int len )  
{  
    unsigned int ra;  

    printf("good packet:");
    for(ra=0;ra<len;ra++) printf("%02X",data[ra]);
    printf("\n");
}  
int getbyte ( unsigned char *d )  
{  
    //check peripheral for a new byte  
    //or serialize a packet or file  

    if(testoff<sizeof(testdata))
    {
        *d=testdata[testoff++];
        return(1);
    }
    else
    {
        printf("no more test data\n");
        exit(0);
    }
    return(0);
}

int main ( void )  
{  
    unsigned char b;

    state=0; //idle

    while(1)
    {
        if(getbyte(&b))
        {
            switch(state)
            {
                case 0: //idle
                    if(b!=0xFA)
                    {
                        printf("Invalid sync pattern 0x%02X\n",b);
                        break;
                    }
                    packoff=0;
                    checksum=b;
                    packet[packoff++]=b;

                    state++;
                    break;
                case 1: //packet length
                    checksum+=b;
                    packet[packoff++]=b;

                    packlen=b;
                    if(packlen<3)
                    {
                        printf("Invalid packet length %u\n",packlen);
                        state=0;
                        break;
                    }

                    state++;
                    break;
                case 2: //payload
                    checksum+=b;
                    packet[packoff++]=b;

                    if(packoff>=packlen)
                    {
                        state=0;
                        checksum=checksum&0xFF;
                        if(checksum)
                        {
                            printf("Checksum error 0x%02X\n",checksum);
                        }
                        else
                        {
                            process_packet(packet,packlen);
                        }
                    }
                    break;
            }
        }

        //do other stuff, handle other devices/interfaces

    }
}
少跟Wǒ拽 2024-07-15 10:03:25

国家机器无处不在。 状态机是通信接口的关键,在接收消息时需要对其进行解析。 此外,在嵌入式系统开发中,由于严格的时间限制,我多次需要将一个任务分成多个任务。

State machines are everywhere. State machines are key in communications interfaces where a message needs to be parsed as it is received. Also, there have been many times in embedded systems development that I've needed to separate a task into multiple tasks because of strict timing constraints.

你对谁都笑 2024-07-15 10:03:25

许多数字硬件设计都涉及创建状态机来指定电路的行为。 如果您正在编写 VHDL,那么它会经常出现。

A lot of digital hardware design involves creating state machines to specify the behaviour of your circuits. It comes up quite a bit if you're writing VHDL.

欢你一世 2024-07-15 10:03:25

QA 基础设施,旨在屏幕抓取或以其他方式运行测试过程。 (这是我的特殊经验领域;我为我的最后一个雇主用 Python 构建了一个状态机框架,支持将当前状态推送到堆栈上,并使用各种状态处理程序选择方法以在我们所有基于 TTY 的屏幕抓取工具中使用) 。 该概念模型非常适合,因为通过 TTY 应用程序运行,它会经历有限数量的已知状态,并且可以移回旧状态(考虑使用嵌套菜单)。 该信息已发布(已获得该雇主的许可); 使用Bazaar查看http://web.dyfis.net/bzr/isg_state_machine_framework/< /code> 如果你想查看代码。

工单、流程管理和工作流程系统——如果您的工单有一组规则来确定其在“新”、“已分类”、“进行中”、“需要-QA”、“失败-QA”和“已验证”(例如)之间的移动,那么您就拥有了一个简单的状态机。

构建小型、易于证明的嵌入式系统——交通灯信号是一个关键示例,其中所有可能状态的列表必须被完全枚举和已知。

解析器和词法分析器很大程度上基于状态机,因为确定流入的内容的方式取决于您当时所在的位置。

QA infrastructure, intended to screen-scrape or otherwise run through a process under test. (This is my particular area of experience; I built a state machine framework in Python for my last employer with support for pushing the current state onto a stack and using various methods of state handler selection for use in all our TTY-based screen scrapers). The conceptual model fits well, as running through a TTY application, it goes through a limited number of known states, and can be moved back into old ones (think about using a nested menu). This has been released (with said employer's permission); use Bazaar to check out http://web.dyfis.net/bzr/isg_state_machine_framework/ if you want to see the code.

Ticket-, process-management and workflow systems -- if your ticket has a set of rules determining its movement between NEW, TRIAGED, IN-PROGRESS, NEEDS-QA, FAILED-QA and VERIFIED (for example), you've got a simple state machine.

Building small, readily provable embedded systems -- traffic light signaling is a key example where the list of all possible states has to be fully enumerated and known.

Parsers and lexers are heavily state-machine based, because the way something streaming in is determined is based on where you're at at the time.

笨死的猪 2024-07-15 10:03:25

FSM 适用于具有多个状态并且需要在刺激下转换到不同状态的任何地方。

(事实证明,这涵盖了大多数问题,至少在理论上是这样)

A FSM is used everywhere you have multiple states and need to transition to a different state on stimulus.

(turns out that this encompasses most problems, at least theoretically)

空城旧梦 2024-07-15 10:03:25

正则表达式是有限状态机(或“有限状态自动机”)发挥作用的另一个例子玩。

编译后的正则表达式是一个有限状态机,并且
正则表达式可以匹配的字符串集合正是有限状态自动机可以接受的语言(称为“正则语言”)。

Regular expressions are another example of where finite state machines (or "finite state automata") come into play.

A compiled regexp is a finite state machine, and
the sets of strings that regular expressions can match are exactly the languages that finite state automata can accept (called "regular languages").

白龙吟 2024-07-15 10:03:25

我有一个来自我正在开发的当前系统的示例。 我正在构建一个股票交易系统。 跟踪订单状态的过程可能很复杂,但如果您为订单的生命周期构建状态图,则可以使将新传入交易应用于现有订单变得更加简单。 如果您从当前状态得知新事务只能是三件事之一而不是 20 件事之一,那么应用该事务所需的比较就会少得多。 它使代码更加高效。

I have an example from a current system I'm working on. I'm in the process of building a stock trading system. The process of tracking the state of an order can be complex, but if you build a state diagram for the life cycle of an order it makes applying new incoming transactions to the existing order much simpler. There are many fewer comparisons necessary in applying that transaction if you know from its current state that the new transaction can only be one of three things rather than one of 20 things. It makes the code much more efficient.

千と千尋 2024-07-15 10:03:25

我在这里没有看到任何真正解释我看到它们被使用的原因的内容。

出于实际目的,当程序员被迫在操作中间返回线程/退出时,通常必须添加一个。

例如,如果您有一个多状态 HTTP 请求,您的服务器代码可能如下所示:

Show form 1
process form 1
show form 2
process form 2

问题是,每次显示表单时,您都必须退出服务器上的整个线程(在大多数语言中) ),即使您的代码在逻辑上全部流动在一起并使用相同的变量。

在代码中放置中断并返回线程的行为通常是使用 switch 语句完成的,并创建所谓的状态机(非常基本版本)。

当你变得越来越复杂时,弄清楚哪些状态是有效的就会变得非常困难。 人们通常会定义一个“状态转换表”来描述所有的状态转换。

我编写了一个状态机库,主要概念是您可以实际实现您的直接状态转换表。 这是一个非常巧妙的练习,但不确定它会进行得如何......

I didn't see anything here that actually explained the reason I see them used.

For practical purposes, a programmer usually has to add one when he is forced to return a thread/exit right in the middle of an operation.

For instance, if you have a multi-state HTTP request, you might have server code that looks like this:

Show form 1
process form 1
show form 2
process form 2

The thing is, every time you show a form, you have to quit out of your entire thread on the server (in most languages), even if your code all flows together logically and uses the same variables.

The act of putting a break in the code and returning the thread is usually done with a switch statement and creates what is called a state machine (Very Basic Version).

As you get more complex, it can get really difficult to figure out what states are valid. People usually then define a "State Transition Table" to describe all the state transitions.

I wrote a state machine library, the main concept being that you can actually implement your state transition table directly. It was a really neat exercise, not sure how well it's going to go over though...

末が日狂欢 2024-07-15 10:03:25

有限状态机可用于任何自然语言的形态解析。

从理论上讲,这意味着形态和语法在计算级别之间分开,一个最多是有限状态,另一个最多是轻微的上下文敏感(因此需要其他理论模型来解释单词到单词而不是单词之间的关系)语素与语素的关系)。

这在机器翻译和文字注释领域非常有用。 表面上,它们是为 NLP 中不那么琐碎的机器学习应用(例如句法或依存分析)提取的低成本特征。

如果您有兴趣了解更多信息,可以查看 Beesley 和 Karttunen 的有限状态形态学,以及他们在 PARC 设计的 Xerox Finite State Toolkit。

Finite state machines can be used for morphological parsing in any natural language.

Theoretically, this means that morphology and syntax are split up between computational levels, one being at most finite-state, and the other being at most mildly context sensitive (thus the need for other theoretical models to account for word-to-word rather than morpheme-to-morpheme relationships).

This can be useful in the area of machine translation and word glossing. Ostensibly, they're low-cost features to extract for less trivial machine learning applications in NLP, such as syntactic or dependency parsing.

If you're interested in learning more, you can check out Finite State Morphology by Beesley and Karttunen, and the Xerox Finite State Toolkit they designed at PARC.

缘字诀 2024-07-15 10:03:25

状态驱动代码是实现某些类型逻辑(例如解析器)的好方法。 它可以通过多种方式完成,例如:

  • 状态驱动在给定点实际执行的代码位(即状态隐含在您正在编写的代码段中)。 递归下降解析器是此类代码的一个很好的例子。

  • 状态驱动在条件语句(例如 switch 语句)中执行的操作。

  • 显式状态机,例如由解析器生成工具生成的状态机,例如 LexYacc

并非所有状态驱动代码都用于解析。 通用状态机生成器是 smc。 它吸入状态机的定义(以其语言),并以各种语言吐出状态机的代码。

State driven code is a good way to implement certain types of logic (parsers being an example). It can be done in several ways, for example:

  • State driving which bit of code is actually being executed at a given point (i.e. the state is implicit in the piece of code you are writing). Recursive descent parsers are a good example of this type of code.

  • State driving what to do in a conditional such as a switch statement.

  • Explicit state machines such as those generated by parser generating tools such as Lex and Yacc.

Not all state driven code is used for parsing. A general state machine generator is smc. It inhales a definition of a state machine (in its language) and it will spit out code for the state machine in a variety of languages.

你不是我要的菜∠ 2024-07-15 10:03:25

好的答案。 这是我的 2 美分。 有限状态机是一个理论概念,可以通过多种不同的方式实现,例如表或 while 开关(但不要告诉任何人这是一种“goto 恐怖”的方式)。 任何 FSM 都对应一个正则表达式,反之亦然,这是一个定理。 由于正则表达式对应于结构化程序,因此您有时只需编写结构化程序即可实现 FSM。 例如,一个简单的数字解析器可以按照以下方式编写:

/* implement dd*[.d*] */
if (isdigit(*p)){
    while(isdigit(*p)) p++;
    if (*p=='.'){
        p++;
        while(isdigit(*p)) p++;
    }
    /* got it! */
}

你明白了。 而且,如果有一种方法运行得更快,我不知道它是什么。

Good answers. Here's my 2 cents. Finite State Machines are a theoretical idea that can be implemented multiple different ways, such as a table, or as a while-switch (but don't tell anybody it's a way of saying goto horrors). It is a theorem that any FSM corresponds to a regular expression, and vice versa. Since a regular expression corresponds to a structured program, you can sometimes just write a structured program to implement your FSM. For example, a simple parser of numbers could be written along the lines of:

/* implement dd*[.d*] */
if (isdigit(*p)){
    while(isdigit(*p)) p++;
    if (*p=='.'){
        p++;
        while(isdigit(*p)) p++;
    }
    /* got it! */
}

You get the idea. And, if there's a way that runs faster, I don't know what it is.

晨敛清荷 2024-07-15 10:03:25

一个典型的用例是交通灯。

关于实现说明:Java 5 的枚举可以具有抽象方法,这是封装状态相关行为的绝佳方法。

A typical use case is traffic lights.

On an implementation note: Java 5's enums can have abstract methods, which is an excellent way to encapsulate state-dependent behavior.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文