patternMinor
Finite state machine written in OCaml to test for the sequence 0,1
Viewed 0 times
finitewrittenthesequenceocamlstatetestformachine
Problem
I got inspired by Stack Overflow to build a simple state machine which can test if a sequence contains 0,1. I have two questions:
(If it is matters, I came from Python and many things in OCaml seem unusual to me).
- How can I get rid of line
| _ -> (functionq0 ->q0 |q2 ->
q2 | q1 -> q1)- How can I improve that code?
(If it is matters, I came from Python and many things in OCaml seem unusual to me).
(*
---> q0 ---0--> q2 ---1---> q1
/ \ / \ / \
-1-> -0-> -0,1->
*)
type ('state, 'number) state_machine = {
initial: 'state;
final: 'state -> string;
transition: 'number -> 'state -> 'state;
};;
let state_machine_01 sequence =
let machine_01 = {
initial = `q0;
final = (function `q0 -> "Init" | `q2 -> "Found zero" | `q1 -> "END" );
transition = (function
| 0 -> (function `q0 -> `q2 | `q2 -> `q2 | `q1 -> `q1)
| 1 -> (function `q0 -> `q0 | `q2 -> `q1 | `q1 -> `q1)
| _ -> (function `q0 -> `q0 | `q2 -> `q2 | `q1 -> `q1)
);
} in
let state = ref machine_01.initial in
for i = 0 to (List.length sequence) - 1 do
state := (machine_01.transition (List.nth sequence i)) !state
done;
machine_01.final !state;
;;
let () =
Printf.printf "------------- start --------------- \n";
Printf.printf "%s\n" (state_machine_01 [1; 1; 0; 0; 0; 1; 0; 1]);
Printf.printf "%s\n" (state_machine_01 [1; 1; 0; 0; 0]);
Printf.printf "%s\n" (state_machine_01 [1; 1; 1]);
Printf.printf "-------------- end ---------------- \n";
;;Solution
I notice that you represent states as functions. This does give some expressive power, as seen in the composition example given in your linked answer.
If that power isn't needed we can write things directly and simply:
If you want to stick with the given framework, then you can simplify a bit and transform into a functional style:
If that power isn't needed we can write things directly and simply:
type element = Z | O
let rec start list = look_for_zero list
and look_for_zero = function
| [] -> "nothing"
| Z::rest -> have_zero rest
| O::rest -> look_for_zero rest
and have_zero = function
| [] -> "nothing"
| O::_ -> "yes!"
| Z::rest -> look_for_zero restIf you want to stick with the given framework, then you can simplify a bit and transform into a functional style:
type ('state, 'number) state_machine = {
initial: 'state;
final: 'state -> string;
transition: 'state -> 'number -> 'state; (* I changed the order! *)
};;
type state = Init | HaveZero | FoundZeroOne
type element = Zero | One
let final = function
| Init | HaveZero -> "no"
| FoundZeroOne -> "yes"
let transition state n =
match n, state with
| _, FoundZeroOne -> FoundZeroOne
| Zero, _ -> HaveZero
| One, Init -> Init
| One, HaveZero -> FoundZeroOne
let machine = {
initial = Init;
final;
transition;
}
let run_machine machine list =
machine.final
(List.fold_left machine.transition machine.initial list)Code Snippets
type element = Z | O
let rec start list = look_for_zero list
and look_for_zero = function
| [] -> "nothing"
| Z::rest -> have_zero rest
| O::rest -> look_for_zero rest
and have_zero = function
| [] -> "nothing"
| O::_ -> "yes!"
| Z::rest -> look_for_zero resttype ('state, 'number) state_machine = {
initial: 'state;
final: 'state -> string;
transition: 'state -> 'number -> 'state; (* I changed the order! *)
};;
type state = Init | HaveZero | FoundZeroOne
type element = Zero | One
let final = function
| Init | HaveZero -> "no"
| FoundZeroOne -> "yes"
let transition state n =
match n, state with
| _, FoundZeroOne -> FoundZeroOne
| Zero, _ -> HaveZero
| One, Init -> Init
| One, HaveZero -> FoundZeroOne
let machine = {
initial = Init;
final;
transition;
}
let run_machine machine list =
machine.final
(List.fold_left machine.transition machine.initial list)Context
StackExchange Code Review Q#123723, answer score: 5
Revisions (0)
No revisions yet.