PDA and a regular expression - regular-language

I have a PDA and some regular expression. Is there any algorithm I can use to make sure my PDA accepts strings that are subset of what could be produced by the regular expression ?
Thanks!
Gil

It sounds like you're asking this: given a PDA M and a regular expression r, produce a PDA which accepts the language L(M) intersect L(r). If this is what you want, the answer is yes, and the construction is tedious but straightforward:
transform the regular expression r into a NFA N using some construction, e.g., one used in a constructive proof of the equivalence of regular expressions and finite automata
determinize the NFA N to get a DFA M' using some construction, e.g., the powerset (or subset) construction, or any used in a constructive proof of the equivalence of nondeterministic and deterministic FAs
optionally, minimize M' to get M'', using some DFA minimization algorithm
now, construct the new PDA P as follows:
the states will be all ordered pairs (a, b) where a is a state in the PDA M and b is a state in the DFA M''
the transitions will be from state (a, b) to (a', b') on symbol s whenever a transitions to a' on s in PDA M and b transitions to b' on s in DFA M'' (for epsilon-transitions, go from (a, b) to (a', b)).
the initial state (ai, bi) will be comprised of the initial states ai and bi of the PDA M and DFA M'', respectively
the accepting states will be those where BOTH components are accepting in their respective machines (pairs (a, b) where a is accepting in PDA M and b is accepting in DFA M'')
the stack is updated according to the transitions from PDA M alone
A machine so constructed will accept everything that is both accepted by PDA M and matched by regular expression r.

Related

Composing non-distributive monads in recursion-schemes

One of my favourite things about the recursion schemes in Haskell are the generalised morphisms (gcata etc.) that allow interleaving (co-)monadic computations with recursion, using a monad transformer library. For example, as described in this great blog post.
However, I've run into a problem; to be able to use these functions we need the (co-)monads to be (co-)sequentiable. Consider a type signature for gana:
gana : Monad m => (forall z . m (f z) -> f (m z)) -> (a -> f (m a)) -> a -> b
The first argument essentially says that m must have a sequence operator.
Unfortunately, I've found that in practice, there are monads which are not distributive. For example:
A monad representing a database transaction. When aborted, the transaction can be rolled back; if sequenced, it can only be rolled back to the point where it was sequenced.
A concurrency monad, representing a lock on a resource, or an atomic computation. When sequenced, the lock is lost momentarily.
In this case, it is still possible to write a specialised recursion scheme that interleaves the monadic execution; but you lose the ability to fuse it using a monad transformer. i.e. if you want to combine such non-distributive monads, they can not be fused using a transformer with the monad/comonad in the f-(co)algebra. Concretely, I couldn't use a monad transformer to combine a DBTransaction monad with an apomorphism (ExceptT/EitherT); I'd need to write a custom recursion-scheme from scratch.
My question is whether anyone has suggestions for working around this limitation.

What does a nontrivial comonoid look like?

Comonoids are mentioned, for example, in Haskell's distributive library docs:
Due to the lack of non-trivial comonoids in Haskell, we can restrict ourselves to requiring a Functor rather than some Coapplicative class.
After a little searching I found a StackOverflow answer that explains this a bit more with the laws that comonoids would have to satisfy. So I think I understand why there's only one possible instance for a hypothetical Comonoid typeclass in Haskell.
Thus, to find a nontrivial comonoid, I suppose we'd have to look in some other category. Surely, if category theorists have a name for comonoids, then there are some interesting ones. The other answers on that page seem to hint at an example involving Supply, but I couldn't figure one out that still satisfies the laws.
I also turned to Wikipedia: there's a page for monoids that doesn't reference category theory, which seems to me as an adequate description of Haskell's Monoid typeclass, but "comonoid" redirects to a category-theoretic description of monoids and comonoids together that I can't understand, and there still don't seem to be any interesting examples.
So my questions are:
Can comonoids be explained in non-category-theoretic terms like monoids?
What is a simple example of an interesting comonoid, even if it's not a Haskell type? (Could one be found in a Kleisli category over a familiar Haskell monad?)
edit: I am not sure if this is actually category-theoretically correct, but what I was imagining in the parenthetical of question 2 was nontrivial definitions of delete :: a -> m () and split :: a -> m (a, a) for some specific Haskell type a and Haskell monad m that satisfy Kleisli-arrow versions of the comonoid laws in the linked answer. Other examples of comonoids are still welcome.
As Phillip JF mentioned, comonoids are interesting to talk about in substructural logics. Let's talk about linear lambda calculus. This is much like your normal typed lambda calculus except that every variable must be used exactly once.
To get a feel, let's count linear functions of given types, i.e.
a -> a
has exactly one inhabitant, id. While
(a,a) -> (a,a)
has two, id and flip. Note that in regular lambda calculus (a,a) -> (a,a) has four inhabitants
(a, b) ↦ (a, a)
(a, b) ↦ (b, b)
(a, b) ↦ (a, b)
(a, b) ↦ (b, a)
but the first two require that we use one of the arguments twice while discarding the other. This is exactly the essence of linear lambda calculus—disallowing those kinds of functions.
As a quick aside, what's the point of linear LC? Well, we can use it to model linear effects or resource usage. If, for instance, we have a file type and a few transformers it might look like
data File
open :: String -> File
close :: File -> () -- consumes a file, but we're ignoring purity right now
t1 :: File -> File
t2 :: File -> File
and then the following are valid pipelines:
close . t1 . t2 . open
close . t2 . t1 . open
close . t1 . open
close . t2 . open
but this "branching" computation isn't
let f1 = open "foo"
f2 = t1 f1
f3 = t2 f1
in close f3
since we used f1 twice.
Now, you might be wondering something at this point about what things must follow the linear rules. For instance, I decided that some pipelines don't have to include both t1 and t2 (compare the enumeration exercise from before). Further, I introduced the open and close functions which happily create and destroy the File type despite that being a violation of linearity.
Indeed, we might posit the existence of functions which violate linearity—but not all clients may. It's much like the IO monad—all of the secrets live inside the implementation of IO so that users work in a "pure" world.
And this is where Comonoid comes in.
class Comonoid m where
destroy :: m -> ()
split :: m -> (m, m)
A type that instantiates Comonoid in a linear lambda calculus is a type which has carry-along destruction and duplication rules. In other words, it's a type which isn't very much bound by linear lambda calculus at all.
Since Haskell doesn't implement the linear lambda calculus rules at all, we can always instantiate Comonoid
instance Comonoid a where
destroy a = ()
split a = (a, a)
Or, perhaps the other way to think of it is that Haskell is a linear LC system that just happens to instantiate Comonoid for every type and applies destroy and split for you automatically.
A monoid in the usual sense is the same as a categorical monoid in the category of sets. One would expect that a comonoid in the usual sense is the same as a categorical comonoid in the category of sets. But every set in the category of sets is a comonoid in a trivial way, so apparently there is no non-categorical description of comonoids which would be parallel to that of monoids.
Just like a monad is a monoid in the category of endofunctors (what's the problem?), a comonad is a comonoid in the category of endofunctors (what's the coproblem?) So yes, any comonad in Haskell would be an example of a comonoid.
Well one way we can think of a monoid is as hooked to any particular product construction that we're using, so in Set we'd take this signature:
mul : A * A -> A
one : A
to this one:
dup : A -> A * A
one : A
but the idea of duality is that the logical statements that you can make all have duals which can be applied to the dual objects, and there is another way of stating what a monoid is, and that's being agnostic to the choice of product construction and then when we take the costructure we can take the coproduct in the output, like:
div : A -> A + A
one : A
where + is a tagged sum. Here we essentially have that every single term which is in this type is always ready to produce a new bit, which is implicitly derived from the tag used to denote the left or the right instance of A. I personally think this is really damn cool. I think the cool version of the things that people were talking about above is when you don't particularly construct that for monoids, but for monoid actions.
A monoid M is said to act on a set A if there's a function
act : M * A -> A
where we have the following rules
act identity a = a
act f (act g a) = act (f * g) a
If we want a co-action, what exactly do we want?
act : A -> M * A
this generates us a stream of the type of our comonoid! I'm having a lot of trouble coming up with the laws for these systems, but I think they must be around somewhere so I'm gonna keep looking tonight. If somebody can tell me them or that I'm wrong about these things in some way or another, also interested in that.
As a physicist, the most common example I deal with is coalgebras, which are comonoid objects in the category of vector spaces, with the monoidal structure usually given by the tensor product.
In that case, there is a bijection between monoid and comonoid objects, since you can just take the adjoint or transpose of the product and unit maps to get a coproduct and a counit that satisfy the comonoid axioms.
In some branches of physics, it is very common to see objects that have both an algebra and a coalgebra structure with some compatibility axioms. The two most common cases are Hopf algebras and Frobenius algebras. They are very convenient for constructing states or solution that are entangled or correlated.
In programming, the simplest nontrivial example I can think of would be reference counted pointers such as shared_ptr in C++ and Rc in Rust, along with their weak equivalents. You can copy them, which is a nontrivial operation that bumps up the refcount (so the two copies are distinct from the initial state). You can drop (call the destructor) on one, which is nontrivial because it bumps down the refcount of any other refcounted pointer that points to the same piece of data.
Furthermore, weak pointers are a great example of a comonoid action. You can use the co-action to generate a weak pointer from a shared pointer. This can be easily checked by noting that creating one from a shared pointer and immediately dropping it is a unit operation, and creating one & cloning it is equivalent to creating two from the shared pointer.
This is a general thing you see with nontrivial coproducts and their co-actions: when they don't reduce to a copying operation, they intuitively imply some form of action at a distance between the two halves, while also adding an operation that erases one half to leave the other independent.

why are the state and reader monads functions while the writer monad is a tuple?

I'm a Haskell newbie, and I think I understand monads and their mechanics (at least for the list, state, maybe, writer and reader monads), but I want to understand why they have been defined the way they have, or why they have to be the way they are, to aid in my intuition in thinking about them.
Specifically, what is it about reading that makes the reader or state monads need to be functions (i.e. \s -> (a,s) ), and not just data like the writer monad (i.e. (w,a) )?
Also, could a writer monad be used as a state monad, where the log is used as a string representation of state, as long as the MonadPlus functionality is not used? Is the monadic function used with writer monads allowed to look at the current log and modify if at will, or is it only the writer monad's bind function that is allowed to look at the log?
Also, why are monads defined in terms of monadic functions that with type a -> m b, instead of with type m a -> mb? What's so natural about a function going from a base type to a monad wrapped type?
Thanks for your answers.
The state and reader monad both depend on the value of whatever state we're interested in.
We need to be able to access it otherwise how could we write something like
foo = do
i <- get
return $ if i == 1 then 2 else 3
So our state monad naturally looks like something that takes in a state, does stuff, and produces a new one.
Likewise with the reader monad, we take in some state, magic, and produce an output (but no new state since it's Reader s a <=> s -> a.
Now this is very different than the writer monad. In the writer, we don't care about what's been stuck in the state previously, all we want to do is take our current state, and jam some more stuff in there. Because our state is a monoid, we have a guaranteed start state mempty and a way to jam stuff in mappend. This means that we can "run" each computation in an empty context so to speak and just fuse the outputs together and get identical results.
Ok, now there's about a few questions so I'll go one at a time
If the writer monad had access to the previously written results, then it's going to look like s -> (s, a) which is the state monad :) So yes, whatever you could do with the state monad could be done with this augmented writer.
In fact both the StateT and WriterT monads have MonadPlus instances so I'm not sure what you're getting at here..
Since there isn't an arbitrary function m a -> a, we need some way to unwrap a computation to view the results ala >>=, and since return :: a -> m a makes it trivial to go the other way, it's more general to go from plain to monadic value. Otherwise we'd just have these useless IO String, STM Int and whatnot that we couldn't depend on for the rest of our computation since fmap won't let us hoist in more side effects.
They're defined differently because they do different things.
Take the reader monad. Start by thinking about what it means, not about how it works.
A computation in the reader monad is one that depends on an extra piece of information, the reader's "environment". So a Reader Env Int is an Int that depends on the environment (of type Env); if I evaluate it with one environment I'll get one Int value, and if I evaluate it with a different environment I'll get another Int value. If I don't have an environment I can't know what value the Reader env Int is.
Now, what kind of value will give me an Int if I give it an Env? A function of type Env -> Int! So that generalises to e -> a being a monad for each e (with a being the type parameter of the monad; (->) e if you like the prefix notation).
Now lets think about the meaning of the writer monad. A computation in the writer monad produces a value, but it also produces an extra value "on the side": the "log" value. And when we bind together a series of monadic computations from in the writer monad, the log values will be combined (if we require the log type to be a monoid, then this guarantees log values can be combined with no other knowledge about what they are). So a Writer Log Int is an Int that also comes with value of type Log.
That sounds a lot like simply a pair: (Log, Int). And that generalises to (w, a) being a monad for each w (with a being the type parameter of the monad). The monoid constraint on w that guarantees we can combine the log values also means that we have an obvious starting value (the identity element for the monoid: mempty), so we don't need to provide anything to get a value out of a value in the writer monad.
The reasoning for the state monad to be s -> (a, s) is actually pretty much a combination of the above; a State S Int is an Int that both depends on an S value (as the reader depends on the environment) and also produces an S value, where binding together a sequence of state computations should result in each one "seeing" the state produced by the previous one. A value that depends on a state value is a function of the state value; if the output comes "along with" a new state value then we need a pair.
Also, why are monads defined in terms of monadic functions that with type a -> m b, instead of with type m a -> m b? What's so natural about a function going from a base type to a monad wrapped type?
(I took the libery of adding a space between m and b in mb).
See, that's what makes it a monad. Without this, we already have functions a -> b and a link from these to f a -> f b (this link is called "functor", and obeys the laws for fmap). But functor only gives you a projection of one "world" (a category) into the other - so that whatever laws hold in the first world, they also hold in the second world (for example, if a + b == c, then f a (f +) f b == f c). The monad gives you a bridge between the "worlds".
Also, you don't have to define the monad in terms of behaviour with functions of type a -> m b, but one minimal specification of a monad tells you how >>=, return, id and (.) relate. It is possible to define the monad using >=>, return, id and (.), or using join, return, id and (.) - you see, it doesn't really matter which function to pick. It turns out, >>= is convenient for chaining.
Specifically, what is it about reading that makes the reader or state monads need to be functions (i.e. \s -> (a,s) ), and not just data like the writer monad (i.e. (w,a) )?
Functions are just data. These just happen to be the types which fit the desired semantics best.
Also, could a writer monad be used as a state monad, where the log is used as a string representation of state, as long as the MonadPlus functionality is not used?
You couldn't pass non-empty initial state, and couldn't modify it other than by appending values. If you do change this, you get the standard state monad (except for strings only).
Is the monadic function used with writer monads allowed to look at the current log and modify if at will, or is it only the writer monad's bind function that is allowed to look at the log?
You'll note the Writer monad has a tell function which actually adds new data to the log.
Also, why are monads defined in terms of monadic functions that with type a -> m b, instead of with type m a -> m b? What's so natural about a function going from a base type to a monad wrapped type?
I think the best answer is "because a -> m b turns out to be more useful".

Is 'Chaining operations' the "only" thing that the Monad class solves?

To clarify the question: it is about the merits of the monad type class (as opposed to just its instances without the unifying class).
After having read many references (see below),
I came to the conclusion that, actually, the monad class is there to solve only one, but big and crucial, problem: the 'chaining' of functions on types with context. Hence, the famous sentence "monads are programmable semicolons".
In fact, a monad can be viewed as an array of functions with helper operations.
I insist on the difference between the monad class, understood as a general interface for other types; and these other types instantiating the class (thus, "monadic types").
I understand that the monad class by itself, only solves the chaining of operators because mainly, it only mandates its type instances
to have bind >>= and return, and tell us how they must behave. And as a bonus, the compiler greatyly helps the coding providing do notation for monadic types.
On the other hand,
it is each individual type instantiating the monad class which solves each concrete problem, but not merely for being a instance of Monad. For instance Maybe solves "how a function returns a value or an error", State solves "how to have functions with global state", IO solves "how to interact with the outside world", and so on. All theses classes encapsulate a value within a context.
But soon or later, we will need to chain operations on such context-types. I.e., we will need to organize calls to functions on these types in a particular sequence (for an example of such a problem, please read the example about multivalued functions in You could have invented monads).
And you get solved the problem of chaining, if you have each type be an instance of the monad class.
For the chaining to work you need >>= just with the exact signature it has, no other. (See this question).
Therefore, I guess that the next time you define a context data type T for solving something, if you need to sequence calls of functions (on values of T) consider making T an instance of Monad (if you need "chaining with choice" and if you can benefit from the do notation). And to make sure you are doing it right, check that T satisfies the monad laws
Then, I ask two questions to the Haskell experts:
A concrete question: is there any other problem that the monad class solves by ifself (leaving apart monadic classes)? If any, then, how it compares in relevance to the problem of chaining operations?
An optional general question: are my conclusions right, am I misunderstanding something?
References
Tutorials
Monads in pictures Definitely worth it; read this one first.
Fistful of monads
You could have invented monads
Monads are trees (pdf)
StackOverflow Questions & Answers
How to detect a monad
On the signature of >>= monad operator
You're definitely on to something in the way that you're stating this—there are many things that Monad means and you've separated them out well.
That said, I would definitely say that chaining operations is not the primary thing solved by Monads. That can be solved using plain Functors (with some trouble) or easily with Applicatives. You need to use the full monad spec when "chaining with choice". In particular, the tension between Applicative and Monad comes from Applicative needing to know the entire structure of the side-effecting computation statically. Monad can change that structure at runtime and thus sacrifices some analyzability for power.
To make the point more clear, the only place you deal with a Monad but not any specific monad is if you're defining something with polymorphism constrained to be a Monad. This shows up repeatedly in the Control.Monad module, so we can examine some examples from there.
sequence :: [m a] -> m [a]
forever :: m a -> m b
foldM :: (a -> b -> m a) -> a -> [b] -> m a
Immediately, we can throw out sequence as being particular to Monad since there's a corresponding function in Data.Traversable, sequenceA which has a type slightly more general than Applicative f => [f a] -> f [a]. This ought to be a clear indicator that Monad isn't the only way to sequence things.
Similarly, we can define foreverA as follows
foreverA :: Applicative f => f a -> f b
foreverA f = flip const <$> f <*> foreverA f
So more ways to sequence non-Monad types. But we run into trouble with foldM
foldM :: (Monad m) => (a -> b -> m a) -> a -> [b] -> m a
foldM _ a [] = return a
foldM f a (x:xs) = f a x >>= \fax -> foldM f fax xs
If we try to translate this definition to Applicative style we might write
foldA :: (Applicative f) => (a -> b -> f a) -> a -> [b] -> f a
foldA _ a [] = pure a
foldA f a (x:xs) = foldA f <$> f a x <*> xs
But Haskell will rightfully complain that this doesn't typecheck--each recursive call to foldA tries to put another "layer" of f on the result. With Monad we could join those layers down, but Applicative is too weak.
So how does this translate to Applicatives restricting us from runtime choices? Well, that's exactly what we express with foldM, a monadic computation (a -> b -> m a) which depends upon its a argument, a result from a prior monadic computation. That kind of thing simply doesn't have any meaning in the more purely sequential world of Applicative.
To solve the problem of chaining operations on an individual monadic type, it's not at all necessary to make it an instance of Monad and be sure the monad laws are satisfied. You could just implement a chaining operation directly on your type.
It would probably be very similar to the monadic bind, but not necessarily exactly the same (recall that bind for lists is concatMap, a function that exists anyway, but with the arguments in a different order). And you wouldn't have to worry about the monad laws, because you would have a slightly different interface for each type, so they wouldn't have any common requirements.
To ask what problem the Monad type class itself solves, look at all the functions (in Control.Monad and else where) that work on values in any monadic type. The problem solved is code reuse! Monad is exactly the part of all the monadic types that is common to each and every one of them. That part is sufficient on its own to write useful computations. All of these functions could be implemented for any individual monadic type (often more directly), but they've already been implemented for all monadic types, even the ones that don't exist yet.
You don't write a Monad instance so that you can chain operations on your type (often you already have a way of chaining, in fact). You write a Monad instance for all the code that automatically comes along with the Monad instance. Monad isn't about solving any problem for any single type, it's about a way of viewing many disparate types as instances of a single unifying concept.

Data structure to represent automata

I'm currently trying to come up with a data structure that fits the needs of two automata learning algorithms I'd like to implement in Haskell: RPNI and EDSM.
Intuitively, something close to what zippers are to trees would be perfect: those algorithms are state merging algorithms that maintain some sort of focus (the Blue Fringe) on states and therefore would benefit of some kind of zippers to reach interesting points quickly. But I'm kinda lost because a DFA (Determinist Finite Automaton) is more a graph-like structure than a tree-like structure: transitions can make you go back in the structure, which is not likely to make zippers ok.
So my question is: how would you go about representing a DFA (or at least its transitions) so that you could manipulate it in a fast fashion?
Let me begin with the usual opaque representation of automata in Haskell:
newtype Auto a b = Auto (a -> (b, Auto a b))
This represents a function that takes some input and produces some output along with a new version of itself. For convenience it's a Category as well as an Arrow. It's also a family of applicative functors. Unfortunately this type is opaque. There is no way to analyze the internals of this automaton. However, if you replace the opaque function by a transparent expression type you should get automata that you can analyze and manipulate:
data Expr :: * -> * -> * where
-- Stateless
Id :: Expr a a
-- Combinators
Connect :: Expr a b -> Expr b c -> Expr a c
-- Stateful
Counter :: (Enum b) => b -> Expr a b
This gives you access to the structure of the computation. It is also a Category, but not an arrow. Once it becomes an arrow you have opaque functions somewhere.
Can you just use a graph to get started? I think the fgl package is part of the Haskell Platform.
Otherwise you can try defining your own structure with 'deriving (Data)' and use the "Scrap Your Zipper" library to get the Zipper.
If you don't need any fancy graph algorithms you can represent your DFA as a Map State State. This gives you fast access and manipulation. You also get focus by keeping track of the current state.
Take a look at the regex-tdfa package: http://hackage.haskell.org/package/regex-tdfa
The source is pretty complex, but it's an implementations of regexes with tagged DFAs tuned for performance, so it should illustrate some good practices for representing DFAs efficiently.

Resources