58 lines
1.7 KiB
FSharp
58 lines
1.7 KiB
FSharp
module NFA
|
|
|
|
open System
|
|
|
|
type State = { name: String }
|
|
|
|
/// A non-deterministic finite automaton
|
|
type NFA = {
|
|
/// All possible characters
|
|
sigma: Char list
|
|
/// All possible states
|
|
states: State list
|
|
/// All possible transitions
|
|
delta: State -> Char -> State list
|
|
/// The state this NFA begins in
|
|
beginState: State
|
|
/// The states in which this NFA accepts
|
|
/// the word
|
|
acceptingStates: State list
|
|
}
|
|
|
|
/// Returns a list of possible states after this charater
|
|
/// was read
|
|
let processChar (nfa: NFA) (state: State) (char: Char) =
|
|
nfa.delta state char
|
|
|
|
/// Returns a list of possible states after this character
|
|
/// list was read
|
|
let rec processCharArray (nfa: NFA) (states: State list) (charArr: Char list) : State list =
|
|
match charArr with
|
|
| [] -> states
|
|
| head :: tail ->
|
|
processCharArray
|
|
nfa
|
|
(
|
|
// Look at all states
|
|
states
|
|
// Where are we going to from each state
|
|
// if we read this character
|
|
|> List.map (fun x -> processChar nfa x head)
|
|
// Which entries are not empty
|
|
|> List.filter (List.isEmpty >> not)
|
|
// If there are no states left,
|
|
// return an empty list
|
|
|> (fun x ->
|
|
if not (List.isEmpty x) then
|
|
List.reduce List.append x
|
|
else [])
|
|
)
|
|
tail
|
|
|
|
/// Returns whether this NFA accepts this word
|
|
let acceptsWord nfa word =
|
|
match processCharArray nfa [nfa.beginState] (Seq.toList word) with
|
|
| [] -> false
|
|
| x -> x
|
|
|> List.map (fun x -> List.contains x nfa.acceptingStates)
|
|
|> List.exists id
|