Begin extracting Dfa and Nfa commonalities
This commit is contained in:
parent
c13ab29ce9
commit
33ed11abc4
1 changed files with 92 additions and 0 deletions
92
src/Rextra/Fa.hs
Normal file
92
src/Rextra/Fa.hs
Normal file
|
|
@ -0,0 +1,92 @@
|
||||||
|
{-# LANGUAGE MultiParamTypeClasses #-}
|
||||||
|
{-# LANGUAGE NamedFieldPuns #-}
|
||||||
|
|
||||||
|
-- | This module contains ways to represent finite automata and their
|
||||||
|
-- execution/evaluation.
|
||||||
|
|
||||||
|
module Rextra.Fa
|
||||||
|
( FaState(..)
|
||||||
|
, Fa
|
||||||
|
, fa
|
||||||
|
, stateMap
|
||||||
|
, entryState
|
||||||
|
, exitStates
|
||||||
|
, states
|
||||||
|
, getState
|
||||||
|
, Executable(..)
|
||||||
|
, transitionAll
|
||||||
|
, execute
|
||||||
|
) where
|
||||||
|
|
||||||
|
import Data.List
|
||||||
|
import qualified Data.Map as Map
|
||||||
|
import qualified Data.Set as Set
|
||||||
|
|
||||||
|
-- | The state of a finite automaton.
|
||||||
|
class FaState state where
|
||||||
|
-- | All the states that can be reached (by any sort of transition)
|
||||||
|
-- from this state.
|
||||||
|
canReach :: state s t -> Set.Set s
|
||||||
|
|
||||||
|
-- | A finite automaton.
|
||||||
|
data Fa state s t = Fa
|
||||||
|
{ stateMap :: Map.Map s (state s t)
|
||||||
|
-- ^ A 'Map.Map' from state indentifiers to states. See 'states',
|
||||||
|
-- 'getState'.
|
||||||
|
, entryState :: s
|
||||||
|
-- ^ The state at which execution of the automaton begins.
|
||||||
|
, exitStates :: Set.Set s
|
||||||
|
-- ^ The automaton's accepting states, i. e. the states that
|
||||||
|
-- determine whether the automaton accepts a certain word.
|
||||||
|
}
|
||||||
|
|
||||||
|
-- | @'states' fa@ are the identifiers of all states contained in @fa@.
|
||||||
|
states :: Fa state s t -> Set.Set s
|
||||||
|
states Fa{stateMap} = Map.keysSet stateMap
|
||||||
|
|
||||||
|
-- | @'getState' fa s@ retrieves the @state s t@ corresponding to the
|
||||||
|
-- identifer @s@.
|
||||||
|
--
|
||||||
|
-- __Warning__: This function is unsafe. It only works if @s@ is a
|
||||||
|
-- member of @'states' fa@, and errors otherwise.
|
||||||
|
getState :: (Ord s) => Fa state s t -> s -> state s t
|
||||||
|
getState Fa{stateMap} s = stateMap Map.! s
|
||||||
|
|
||||||
|
integrityCheck :: (FaState state, Ord s) => Fa state s t -> Bool
|
||||||
|
integrityCheck fa'@Fa{stateMap, entryState, exitStates} =
|
||||||
|
let reachable = map canReach $ Map.elems stateMap
|
||||||
|
mentioned = Set.unions $ Set.singleton entryState : exitStates : reachable
|
||||||
|
in mentioned `Set.isSubsetOf` states fa'
|
||||||
|
|
||||||
|
-- | Construct a 'Fa'.
|
||||||
|
--
|
||||||
|
-- This constructor function also checks whether the finite
|
||||||
|
-- automaton's invariants (see 'getState') hold true.
|
||||||
|
fa :: (FaState state, Ord s) => Map.Map s (state s t) -> s -> Set.Set s -> Maybe (Fa state s t)
|
||||||
|
fa stateMap entryState exitStates =
|
||||||
|
let potentialFa = Fa{stateMap, entryState, exitStates}
|
||||||
|
in if integrityCheck potentialFa then Just potentialFa else Nothing
|
||||||
|
|
||||||
|
-- | A special type class for automata that can be executed. These
|
||||||
|
-- automata must not necessarily be finite.
|
||||||
|
class Executable a execState where
|
||||||
|
-- | The state at which execution of the automaton begins.
|
||||||
|
startState :: a s t -> execState
|
||||||
|
-- | A function that determines the automaton's next state based on
|
||||||
|
-- a token.
|
||||||
|
transition :: a s t -> execState -> t -> execState
|
||||||
|
-- | Whether the automaton acceps
|
||||||
|
accepts :: a s t -> execState -> Bool
|
||||||
|
|
||||||
|
-- | Perform all transitions corresponding to a word (or list) of tokens, in order.
|
||||||
|
transitionAll :: (Executable a execState) => a s t -> execState -> [t] -> execState
|
||||||
|
transitionAll a = foldl' (transition a)
|
||||||
|
|
||||||
|
-- | Like 'transitionAll', starting with the automaton's 'startState'.
|
||||||
|
--
|
||||||
|
-- To check, whether an automaton @a@ accepts a word @w@, use
|
||||||
|
-- 'accepts' like this:
|
||||||
|
--
|
||||||
|
-- > a `accepts` execute a w
|
||||||
|
execute :: (Executable a execState) => a s t -> [t] -> execState
|
||||||
|
execute a = transitionAll a (startState a)
|
||||||
Loading…
Add table
Add a link
Reference in a new issue