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