2

I'm writing an implementation for a non-deterministic finite state automaton (NFA) which has the goal to accurately convey information about the state set through types, which can be reasoned through type algebra.

The mathematical typing definition of the transition function for an NFA is Q ⨯ (Σ ∪ ε) → P(Q), where Q is the set of states, Σ is the set of symbols, ε is the empty symbol, and P(Q) is the power set of Q.

My current implementation models the transition function as transition :: s -> Maybe a -> [s]. Although this makes use of the List Monad's non-determinism feature, it doesn't convey accurate typing information.

Since a -> b is equivalent to b^a in type algebra, I thought of modelling the power set (which contains 2^|Q| elements) as the characteristic function s -> Bool (2^s), leading to the following type definition for the transition function:

newtype Set s = Set (s -> Bool)
transition :: s -> Maybe a -> Set s

Although I've been able to implement basic operations for sets such as union and intersection, I haven't been able to find a way to do non-deterministic computations on values of type Set s.

I have thought of two approaches:

  1. Traversing the domain of the function (s -> Bool)

    • Haskell has no built-in way to do this
  2. Following the bind implementation for the List Monad

So, my question is: is it possible to perform non-deterministic computations on values of a set modelled by the characteristic function, and if it is, how could it be achieved?

Sunderam Dubey
  • 1
  • 11
  • 20
  • 40
  • 3
    You can do approach 1 by constraining `s` with a type class, such as [the `Finite` type class here](https://hackage.haskell.org/package/universe) – David Young Sep 02 '22 at 02:51
  • 3
    Keep in mind that it is quite common to find "isomorphic" data type representations which however exhibit very different computational properties. For instance, a finite set could be represented as a (finite) list or as a balanced BST, but the latter can be much faster on large sets. Using a function `s->Bool` to represent a set is intuitively fine if all you want to do is to test set membership, but will make it hard to perform other operations efficiently. There is a reason why e.g. `Data.Set` does not use that representation, after all. – chi Sep 02 '22 at 10:56
  • Can you be a bit more specific about what non-deterministic computations you want to do? – Daniel Wagner Sep 02 '22 at 14:11
  • @DanielWagner I want to implement the `next` function that can be found [here](https://github.com/edusporto/automata/blob/18e18957d8d941ff4f10151b4e23949b7ceb1458/src/Automata/Regular/NFA.hs) with the following type: `next :: (s -> Maybe a -> Set s) -> Set s -> a -> Set s`. I've been able to concatenate the resulting sets from the transition functions, but I can't figure out if it's possible to non-deterministically choose the next states with that definition of a Set (as I was doing with the List Monad) – Eduardo Porto Sep 02 '22 at 14:24
  • I implemented some state machine stuff here if you want to have a dive at another approach: https://github.com/L0neGamer/state-machine-sim – L0neGamer Sep 03 '22 at 11:24

1 Answers1

1

I guess you could do something like:

bind :: Universe a => Set a -> (a -> Set b) -> Set b
bind (Set m) f = Set (\b -> any ($b) [bs | a <- universe, m a, let Set bs = f a])

This uses the universe package.

Whether you want to share the value computed by the list comprehension between invocations of the lambda is a memory/time tradeoff that you'll have to think through and/or measure yourself.

Daniel Wagner
  • 145,880
  • 9
  • 220
  • 380
  • Thanks, I'll try this later today and mark the answer as correct if it ends up working – Eduardo Porto Sep 02 '22 at 14:28
  • 1
    The parameter `m` is unused in the right hand side. It seems the representation of sets is as a function `a -> Bool` so perhaps it should be `a <- elementsOf m` where `elementsOf (Set m) = filter m universe` ? – user2407038 Sep 02 '22 at 14:49