Functional programming 如何用Ocaml表示一个简单的有限状态机? 我用C++和java编写了一些状态机,但是从来没有用OcAML这样的函数语言。
问题是,我不知道我是否可以只修改来自对象语言版本的代码,因为Ocaml中的记录和变体比类更强大 所以,我需要一个事件驱动的有限状态机(类似于UML中的层次结构),易于配置 有经验的人能举个简单的例子吗?只是为了避免最常见的陷阱 谢谢:)Functional programming 如何用Ocaml表示一个简单的有限状态机? 我用C++和java编写了一些状态机,但是从来没有用OcAML这样的函数语言。,functional-programming,ocaml,state,fsm,Functional Programming,Ocaml,State,Fsm,问题是,我不知道我是否可以只修改来自对象语言版本的代码,因为Ocaml中的记录和变体比类更强大 所以,我需要一个事件驱动的有限状态机(类似于UML中的层次结构),易于配置 有经验的人能举个简单的例子吗?只是为了避免最常见的陷阱 谢谢:) 编辑16/03:是否可以在没有可变状态的情况下进行编辑? 我想把它恰当地封装在“FSM”的名称下,我应该选择一个模块还是一个类?这里有一个极好的答案,它展示了OCaml在表示有限状态机时的表现力和优雅性: 对于更重要的用途,您可以尝试查看一些有限状态机库,如f
编辑16/03:是否可以在没有可变状态的情况下进行编辑?
我想把它恰当地封装在“FSM”的名称下,我应该选择一个模块还是一个类?这里有一个极好的答案,它展示了OCaml在表示有限状态机时的表现力和优雅性:
对于更重要的用途,您可以尝试查看一些有限状态机库,如fsm库。通常,您创建一个与自动机状态相对应的记录,并为触发转换到另一状态的事件创建另一种类型。在状态记录中,您可以为每个事件找到新状态的映射 假设您的转换由字符串触发:
type event = string
module EventMap = Map.Make(struct
type t = event
let compare = compare
end)
type state = {
state_info : ...; (* the content of that state, id, comment, etc. *)
mutable state_transitions : state EventMap.t;
}
let next_state current_state event =
try
EventMap.find event current_state.state_transitions
with Not_found -> current_state
在这里,我假设未知事件保持相同的状态,但记录中可能有错误状态…我最近在OCaml中创建了一个FSM模块,您可以找到它 我对我的FSM实现有一些特殊的要求,这可能会使它看起来不像其他人在这里指出的那样好,但是,我认为你声明FSM本身的方式是一种好的声明方式。特殊要求是,除了能够在OCaml版本中模拟FSM的操作外,我还需要能够从FSM的声明性描述中生成HDL(硬件描述语言)代码。因此,我需要使用谓词表达式,而不是转换函数(否则,我将如何将函数转换为字符串?),因此,您主要希望关注那里的FSM模块以及那里的create和eval_FSM函数 下面是一个用法示例:
(*********************************************************
* FSM testing *******************************************
*)
(* inputs to the FSM *)
let full = Var({name ="full"; value = F});;
let ten_minutes = Var({name = "ten_minutes"; value = F});;
let empty = Var({name = "empty"; value = F});;
let five_minutes = Var({name = "five_minutes"; value =F});;
(* T is true, F is false *)
let _ =
assign full F ;
assign ten_minutes F ;
assign empty F ;
assign five_minutes F ;;
(* outputs from the FSM *)
let water_on = Var({name = "water_on"; value = F});;
let agitate = Var({name = "agitate"; value = F});;
let drain = Var({name = "drain" ; value = F});;
let start_timer = Var({name = "start_timer"; value = F});;
let motor_on = Var({name = "motor_on"; value = F});;
let washed = Var({name = "washed"; value = F});;
let soap = Var({name = "soap"; value = F});;
let reset_actions =
assign water_on F;
assign agitate F;
assign drain F;
assign start_timer F;
assign motor_on F;;
module WashStates =
struct
type t = START | FILL | WASH | DRAIN | RINSE | SPIN | STOP
deriving(Show, Enum)
let start_state = START
end
module LogicExp =
struct
type t = boolean Logic.bexp
type var_t = boolean Logic.variable
let eval_exp exp = to_bool (Logic.eval exp)
let var_to_s = var_to_s
end
module WashFSM = FSM(WashStates)(LogicExp)
open WashStates
(* declare the state table *)
(* CS, PREDICATE, NS, ACTIONs *)
let my_fsm = [
(START, Const(T), FILL, [(water_on, T);
(soap, T)]);
(FILL, Bop(And,full,soap), WASH, [(water_on, F);
(agitate, T);
(washed, T);
(start_timer,T)]);
(WASH, ten_minutes, DRAIN,[(agitate, F);
(start_timer,F);
(empty, T)]);
(DRAIN, Bop(And,empty,soap), FILL, [(drain, F);
(soap, F);
(water_on, T)] );
(FILL, Bop(And,full,Not(soap)), RINSE,[(water_on, F);
(soap, F);
(empty, F);
(agitate, T)]);
(RINSE, ten_minutes, DRAIN, [(agitate, F);
(empty, T)] );
(DRAIN, Bop(And,empty,Not(soap)), SPIN, [(motor_on, T);
(start_timer,T)]);
(SPIN, five_minutes, STOP, [(water_on, F);
(drain, F);
(start_timer,F);
(motor_on, F)]);
(STOP, Const(T), STOP, [(motor_on, F)]);
];;
let st_table, current_state = WashFSM.create my_fsm in
let _ = assign full T in
let current_state = WashFSM.eval_fsm st_table current_state in
let _ = assign ten_minutes T in
let current_state = WashFSM.eval_fsm st_table current_state in
let current_state = WashFSM.eval_fsm st_table current_state in
let _ = (assign ten_minutes F);(assign empty T) in
let current_state = WashFSM.eval_fsm st_table current_state in
let _ = assign five_minutes T in
let current_state = WashFSM.eval_fsm st_table current_state in
let _ = assign five_minutes F in
let _ = assign ten_minutes T in
let current_state = WashFSM.eval_fsm st_table current_state in
let current_state = WashFSM.eval_fsm st_table current_state in
let _ = assign five_minutes T in
let _ = WashFSM.eval_fsm st_table current_state in
(*...and so on...*)
(请原谅“;”结尾-我希望能够将此代码剪切并粘贴到REPL中)
这里使用的一些代码可以在MyGithub上的中找到(fsm.ml是该项目的一部分)。谓词表达式的计算结果为T或F(true或false)。如果为true,则从当前状态转换到下一个状态。Const T表示总是转换。一种表达方式,如:
Bop(And, full, soap)
表示如果full和soap都是T(true),则表达式的计算结果为true。这取决于您必须如何操作FSM,例如,您是否需要存储其状态并稍后继续,或者您是否只想立即执行它。在后一种情况下,将其作为一组尾部递归函数来执行是很简单的 例如,假设regexp
C((A | B)*
——以下相互递归函数是各个FSM的直接实现,它们识别与此regexp匹配的列表(如果我没有犯任何错误:):
每个函数只对应于自动机的一个状态,并实现其转换函数。应用s1:alphabet list->bool
将对参数运行FSM
PS:请注意,这是一个如何展示尾部调用优化的优点和优雅的应用程序…可能的重复是否可以在没有可变状态的情况下进行?我想用“FSM”这个名字来恰当地封装它,我应该选择一个模块还是一个类?
type alphabet = A | B | C | D
let rec s1 = function
| C :: rest -> s2 rest
| _ -> false
and s2 = function
| [] -> true
| (A | B) :: rest -> s2 rest
| C :: rest -> s3 rest
| _ -> false
and s3 = function
| D :: rest -> s2 rest
| _ -> false