Show that the following grammar is ambiguous - syntax

this grammar was in my midterm exam but I couldn't find two different parse tree it ask to show that it's ambiguous
K -> QK | ε
Q -> Qa | aQb | ab
if I didn't see that it has left recursive I was going to write that is not ambiguous,
thank you.

K -> QK -> QQK -> QQ
-> abQ -> abaQb -> abaQab
-> abaabab
K -> QK -> QQK -> QQQK -> QQQ
-> QaQQ -> abaQQ -> abaabQ
-> abaabab
Edit to add some commentary: I'm not sure there's a good way to solve these. Look for rules that can "do the same thing" (like deriving longer strings), and start there. In this case, the issue is that we can add Q in multiple ways. You can try working backwards as well: imagine strings in the language and how they would be finished in the grammar. If you're looking for the shortest counter examples possible, this is helpful since the ambiguity will typically happen fairly late in these strings.

Related

What is the name of this data strcucture, and where is used?

This data structure is for store words, where each letter is a node of a tree like this.
H -> E -> L -> O(f)
-> L(f)
-> I -> G -> H(f)
-> L -> L(f)
So the root node is H and this has 2 childs, and the (f) indicate that is the end of the word.
Is this a know Data structure, have a name, and have know applications?
Because I want to use it, to save memory in a web scraper, but I read more about these pros and cons if this exists?
This data structure is called TRIE structure which are based on prefix of a string. These are mainly used to visualise strings as a graph
This will help you out
https://medium.com/basecs/trying-to-understand-tries-3ec6bede0014

Why is it impossible to Applicative-traverse arrays? (Or is it?)

While pondering how to best map, i.e. traverse, an a -> Maybe a-Kleisli over an unboxed vector, I looked for an existing implementation. Obviously U.Vector is not Traversable, but it does supply a mapM, which for Maybe of course works just fine.
But the question is: is the Monad constraint really needed? Well, it turns out that even boxed vectors cheat for the Traversable instance: they really just traverse a list, which they convert from/to:
instance Traversable.Traversable Vector where
{-# INLINE traverse #-}
traverse f xs = Data.Vector.fromList Applicative.<$> Traversable.traverse f (toList xs)
mono-traversable does the same thing also for unboxed vectors; here this seems even more gruesome performance-wise.
Now, I wouldn't be surprised if vector was actually able to fuse many of these hacked traversals into a far more efficient form, but still – there seems to be a fundamental problem, preventing us from implementing a traversal on an array right away. Is there any “deep reason” for this inability?
After reading through the relevant source of vector and trying to make mapM work with Applicative I think the reason why Data.Vector.Unboxed.Vector doesn't have a traverse :: (Applicative f, Unbox a, Unbox b) -> (a -> f b) -> Vector a -> f (Vector b) function and Data.Vector.Vector doesn't have a native traverse is the fusion code. The offender is the following Stream type:
-- Data/Vector/Fusion/Stream/Monadic.hs Line: 137
-- | Result of taking a single step in a stream
data Step s a where
Yield :: a -> s -> Step s a
Skip :: s -> Step s a
Done :: Step s a
-- | Monadic streams
data Stream m a = forall s. Stream (s -> m (Step s a)) s
This is used internally to implement mapM. The m will be the same as from your initial call to Data.Vector.Unboxed.mapM. But because the spine of this stream is inside the m functor, it is not possible to work with it if you only have an applicative for m.
See also this issue on the vector GitHub repo: Weaken constraint on mapM.
Disclaimer: I don't really know how fusion works. I don't know how vector works.

Solve ~(P /\ Q) |- Q -> ~P in Isabelle

~(P /\ Q) |- Q -> ~P
I don't know where to start.
Negation confuses me.
I have to solve this in Isabelle (a program), but if someone explains how to solve using natural deduction, it will be enough help.
This is an example that the quality of an SO question is many times determined by an answer, not the question. I kind of give this answer to thank M.Eberl for another useful answer, since I can't make comments.
As to a comment above, that you may be asking a homework question, the comment is valid, but if you're confused by negation, then you're mostly doomed anyway, until you make progress, so even one complete answer wouldn't help you, and here, there's no right answer.
The formula is so basic, except through applying step-by-step rules, it would be hard for anyone to prove that they understand what they're proved, without going through the multitude of tedious steps to do so.
For example:
lemma "~(P ∧ Q) ==> Q --> ~P"
by auto
Surely that gets you nothing, if the requirement is that you demonstrate understanding.
I've largely made progress "by the method of absorption over time", and in his answer, M.Eberl gave a significant outline of the basics of natural deduction. My interest in it was to mess around and see if I could absorb a little more.
As to rule and erule, there is the cheat sheet:
http://www.phil.cmu.edu/~avigad/formal/FormalCheatSheet.pdf
As to the proof of logic by means of Isabelle, Isabelle/HOL is so big and involved, that a little help, once, doesn't get you much, though collectively, it's all important.
A basic, logic equivalency
I learned long ago the equivalent statement of an implication. It's even in HOL.thy, line 998:
lemma disj_not2: "(P | ~Q) = (Q --> P)"
From that, it's easy to see, along with DeMorgon's laws (line 993 of HOL.thy), that you stated an equivalency in your question.
Well, of course, not quite, and that's where all the hassle comes in. Rearranging things, based on trivial equivalencies, to finally prove the equivalency. (While also knowing what the notation means, such as that your |- will be ==>. I use ASCII because I don't trust the graphical in browsers.)
M.Eberl mentioned structured proofs. Consider this one:
lemma "~(P ∧ Q) ==> Q --> ~P"
proof-
fix P Q :: bool
assume "~(P ∧ Q)"
hence "~P ∨ ~Q" by simp
hence "~Q ∨ ~P" by metis
thus "Q --> ~P" by metis
qed
What would I deserve in points, for homework? Nothing much. It's actually a testimony that metis knows how to use basic first-order logic. Otherwise, how did it know to make the jump from ~Q ∨ ~P to Q --> ~P?
Assuming you are talking about Isabelle/HOL, you can use ‘single-step tactics’ like rule, erule, assumption with the basic natural deduction rules. The ones you will probably need for your proposition are:
introduction rules notI, conjI, disjE impI
elimination rules like notE, conjE, disjE, impE
destruction rules like mp (modus ponens), conjunct1, conjunct2
If you want to find out what a particular rule means, just write e.g. thm notI and Isabelle will display the statement of the theorem.
You can set up a goal like
lemma "¬(P ∧ Q) ⟹ Q ⟶ ¬P"
and then write e.g.
apply (rule impI)
to apply the introduction rules for implication, which leaves you with the updated goal state
goal (1 subgoal):
1. ¬ (P ∧ Q) ⟹ Q ⟹ ¬ P
Now you find the next appropriate rule and apply that one etc. until all subgoals are solved. Then you can write done and your proof is complete.
As for assumption and erule: if you end up with a goal that has some P to prove and P is already in the assumptions, you can use apply assumption to solve it. (erule is like rule with assumption chained directly after it and is often convenient for applying elimination rules)
However, this kind of proof is very tedious to do. A better way would be to do the whole proof in Isar, Isabelle's structured proof language. For an introduction to Isar, you can have a look at chapter 5 of Concrete Semantics.
Similar to a JIT compiler, this is a LJEFAATGAA answer (learn just enough from another answer to give an answer).
This is more about what I learned than about what others may learn, which may help others learn; the Isabelle learning curve is quite brutal. I'd think the time has come and gone for the OP's need for help.
Except for M.Eberl's answer to exI and refl behavior explanation needed, it would still be a mystery to me about why rule thm produces specific goal states, for a particular thm, and why rule thm produces the message Failed to apply initial proof method.
Except for the precise outline given by Chris, with the rules and braces, I wouldn't have been able to fill in the precise details. An example that if a person has the time to learn, it's better for them to be given a partial answer, to make them do a little work, than to give them the complete answer.
Two main driving points
After a few comments, I show my proof from the outline. It got me the following understanding from having to work out the details, where I talk as if I know I'm right:
The use of apply(rule thm) is being applied to a combination of the chained facts and the goal statement, where this, in the output, displays one or more chained facts.
Braces start and end a local context/scope. Variables inside and outside the context/scope work as we would expect them to work, that is, as scope normally works in programming languages. So if I state fix P Q :: bool at the beginning of a proof, then state fix Q :: bool in a sub-context, the Q in the sub-context refers to a different variable than the parent-context Q.
Having properly credited Chris, I insert his outline here, so it can easily be compared to the Isar source:
1. ~(P & Q) premise
2. { Q assumption
3. { P assumption
4. P & Q and-introduction 3, 2
5. _|_ negation-elimination 1, 4 }
6. ~P negation-introduction 3-5 }
7. Q -> ~P implication-introduction 2-6
The source:
lemma "~(P & Q) ==> Q --> ~P"
proof-
fix P Q :: bool
assume a1: "~(P & Q)"
{
assume a2: "Q"
{
assume a3: "P"
have a4: "P & Q"
apply(rule conjI) apply(rule a3) by(rule a2)
(* NOTE: have to set 'notE' up right. Next 'hence False' doesn't do it. *)
(* hence False apply(rule) by(metis a1) *)
(* 'rule' applies the default of 'conjI', because there is the fact
'this: P & Q', which comes from 'hence'; 'rule notE' gives an error.*)
from a1 a4
have False (* From 'this' and 'goal': ~(P & Q) ⟹ P & Q ==> False *)
by(rule notE) (* notE: ~P ==> P ==> R *)
}
hence "~P"
apply(rule notI) by(assumption)
}
thus "Q --> ~P"
apply(rule impI) by(assumption)
qed
Understanding scope better
Thinking was being required at my statement have False. I wasn't setting things up right for notE. Just to see if I was on the right track, I would execute sledgehammer, but it wasn't able to prove False within that context.
It was because I was on auto-pilot, and was using fix Q :: bool and fix P :: bool in the two local contexts. I took them out and sledgehammer easily found proofs.
That's an example of a person knowing some logic, but not knowing how to implement the logic correctly in the languages Isabelle/HOL and Isabelle/Isar.
Next, I had to learn how to set up things correctly for apply(rule notE).
Belaboring a point
Part of my understanding about the above source comes from seeing the phrase chained facts in isar-ref.pdf. Minor exposure to the natural deduction rules, along with M.Eberl's explanation about unification, instantiation, and resolution finally helped make sense of what happens in the output panel.
Above, I have hence False commented out, and then use have False. Fortunately, in Isabelle, there are multiple ways to do things, but the goal was to apply notE. Even with that, there are different Isar keywords that can be used to set things up.
Anyway, seeing how chained facts are used with rule was a light-bulb moment. I guess here's effectively what's involved at the statement have False, as it relates to notE:
term "~P ==> P ==> R" (* notE: line 376 of HOL.thy *)
lemma "~(P & Q) ⟹ P & Q ==> False"
by(rule notE)
If I had an account, I would upvote the question to get rid of that -1.
Thanks to Chris for giving the precise outline.
Since you explicitly mentioned natural deduction. In a specific flavour of natural deduction -- where lines are numbered and the scope of assumptions is explicitly marked by boxes (denoted by curly braces below) -- one way of proving your statement is the following:
1. ~(P & Q) premise
2. { Q assumption
3. { P assumption
4. P & Q and-introduction 3, 2
5. _|_ negation-elimination 1, 4 }
6. ~P negation-introduction 3-5 }
7. Q -> ~P implication-introduction 2-6
Actually, since your goal is to prove an implication, you only have one choice at the start, namely implication introduction.
It would be a good exercise to translate the above proof as faithfully as possible into a structured Isar proof (e.g., using what is called "raw proof blocks" and incidentally also denoted by curly braces in Isabelle).

Why doesn't sortBy take (a -> a -> Bool)?

The Haskell sortBy function takes (a -> a -> Ordering) as its first argument. Can anyone educate me as to what the reasoning is there? My background is entirely in languages that have a similar function take (a -> a -> Bool) instead, so having to write one that returns LT/GT was a bit confusing.
Is this the standard way of doing it in statically typed/pure functional languages? Is this peculiar to ML-descended languages? Is there some fundamental advantage to it that I'm not seeing, or some hidden disadvantage to using booleans instead?
Summarizing:
An Ordering is not GT | LT, it's actually GT | EQ | LT (apparently GHC doesn't make use of this under the hood for the purposes of sorting, but still)
Returning a trichotomic value more closely models the possible outcomes of a comparison of two elements
In certain cases, using Ordering rather than a Bool will save a comparison
Using an Ordering makes it easier to implement stable sorts
Using an Ordering makes it clear to readers that a comparison between two elements is being done (a boolean doesn't inherently carry this meaning, though I get the feeling many readers will assume it)
I'm tentatively accepting Carl's answer, and posting the above summary since no single answer has hit all the points as of this edit.
I think Boolean Blindness is the main reason. Bool is a type with no domain semantics. Its semantics in the case of a function like sortBy come entirely from convention, not from the domain the function is operating on.
This adds one level of indirection to the mental process involved in writing a comparison function. Instead of just saying "the three values I can return are less than, equal, or greater", the semantic building blocks of ordering, you say "I want to return less than, so I must convert it to a boolean." There's an extra mental conversion step that's always present. Even if you are well-versed in the convention, it still slows you down a bit. And if you're not well-versed in the convention, you are slowed down quite a bit by having to check to see what it is.
The fact that it's 3-valued instead of 2-valued means you don't need to be quite as careful in your sort implementation to get stability, either - but that's a minor implementation detail. It's not nearly as important as actually having your values have meanings. (Also, Bool is no more efficient than Ordering. It's not a primitive in Haskell. They're both algebraic data types defined in libraries.)
When you sort things, you put them in order; there's not a "truth" value to determine.
More to the point, what would "true" mean? That the first argument is less than the second? Greater than? Now you're overriding "true" to really mean "less than" (or "greater than", depending on how you choose to implement the function). And what if they're equal?
So why not cut out the middle man, so to speak, and return what you really mean?
There's no reason it couldn't. If you look at the ghc implementation, it only checks whether the result is GT or not. The Haskell Report version of the code uses insertBy, which likewise only checks for GT or not. You could write the following and use it without any problem:
sortByBool :: (a -> a -> Bool) -> [a] -> [a]
sortByBool lte = sortBy (\x y -> if lte x y then LT else GT)
sort' :: Ord a => [a] -> [a]
sort' = sortByBool (<=)
Some sorts could conceivably perform optimizations by knowing when elements are EQ, but the implementations currently used do not need this information.
I think there were two separate design decisions:
1) Creating the Ordering type
2) Choosing for sortBy to return an Orderingvalue
The Ordering type is useful for more than just sortBy - for example, compare is the "centerpiece" of the Ord typeclass. Its type is :: Ord a => a -> a -> Ordering. Given two values, then, you can find out whether they're less than, greater than, or equal -- with any other comparison function ((<), (<=), (>), (>=)), you can only rule out one of those three possibilities.
Here's a simple example where Ordering (at least in my opinion) makes a function's intent a little clearer:
f a b =
case compare a b of
GT -> {- something -}
LT -> {- something -}
EQ -> {- something -}
Once you've decided to create the Ordering type, then I think it's natural to use it in places where that's the information you're truly looking for (like sortBy), instead of using Bool as a sort of workaround.
Three valued Ordering is needed to save comparisons in cases where we do need to distinguish the EQ case. In duplicates-preserving sort or merge, we ignore the EQ case, so a predicate with less-then-or-equal semantics is perfectly acceptable. But not in case of union or nubSort where we do want to distinguish the three outcomes of comparison.
mergeBy lte (x:xs) (y:ys)
| lte y x = y : mergeBy lte (x:xs) ys
| otherwise = x : mergeBy lte xs (y:ys)
union (x:xs) (y:ys) = case compare x y of
LT -> x : union xs (y:ys)
EQ -> x : union xs ys
GT -> y : union (x:xs) ys
Writing the latter one with lte predicate is unnatural.

Is this an ambiguous grammar? How should I resolve it?

To preface this, my knowledge of this kind of stuff is puny.
Anyways, I've been developing a context-free grammar to describe the structure of alegbraic expressions so I can teach myself how the CYK parsing algorithm works. I understand how such a structure can work with only infix algebraic expressions, but I cannot understand how to develop a grammar that can handle both the unary and binary definitions of the "-" operator.
For reference, here's the grammar I've written (where S is the start symbol) in CNF:
S -> x
A -> O S
S -> L B
B -> S R
S -> K S
O -> +
O -> -
O -> *
O -> /
O -> ^
K -> -
L -> (
R -> )
The problem is that how can the CYK parsing algorithm know ahead of time whether to decide between S -> K S and A -> O S when it encounters the "-" operator? Is such a grammar context-free anymore? And most importantly, since programming languages can handle languages with both the binary and unary minus sign, how should I reasonably parse this?
This seems like a problem related to finite state automata and I don't remember everything from my coursework, but I wrote a CYK parser in OCaml, so I'll go ahead and take a shot :)
If you're trying to parse an expression like 3- -4 for example, you would have your S -> K S rule consume the -4 and then your A -> O S rule would absorb the - -4. This would eventually work up to the top-most S production rule. You should be careful with the grammar you're using though, since the A production rule you listed cannot be reached from S and you should probably have a S -> S O S rule of some sort.
The way that CYK parsing algorithms work is through backtracking, not through the "knowing ahead of time" that you mentioned in your question. What your CYK algorithm should do is to parse the -4 as a S -> K S rule and then it would try to absorb the second - with the S -> K S rule again because this production rule allows for an arbitrarily long chain of unary -. But once your algorithm realizes that it's stuck with the intermediate parse 3 S, it realizes that it has no production symbols that it can use to parse this. Once it realizes that this is no longer parseable, it will go back and instead try to parse the - as an S -> O S rule instead and continue on its merry way.
This means that your grammar remains context-free since a context-sensitive grammar means that you have terminals on the left side of the production rules, so you're good in that respect. HTH!
The grammar is ambiguous, and the parser cannot decide which case to take.
You should probably use a grammar like the following:
S -> EXPR
EXPR -> (EXPR)
EXPR -> - EXPR
EXPR -> EXPR + EXPR
EXPR -> EXPR - EXPR
// etc...
Grammars based on algebraic expressions are rather difficult to disambiguate. Here are some examples of problems which need to be addressed:
a+b+c naturally creates two parse trees. To resolve this, you need to resolve the ambiguity of the associativity of +. You may wish to let a left-to-right parsing strategy take care of this for you, but careful: exponentiation should probably associate right-to-left.
a+b*c naturally creates two parse trees. To fix this problem, you need to deal with operator precedence.
implicit multiplication (a+bc), if it is allowed, creates all sorts of nightmares, mostly at tokenization.
unary subtraction is problematic, as you mention.
If we want to solve these problems, but still have a fast-parsing grammar specialized for algebra, one approach is to have various "levels" of EXPR, one for each level of binding required by precedence levels. For example,
TERM -> (S)
EXPO -> TERM ^ EXPO
PROD -> PROD * EXPO
PROD -> PROD / EXPO
PROD -> -PROD
SUM -> SUM + PROD
SUM -> SUM - PROD
S -> SUM
This requires that you also allow "promotion" of types: SUM -> PROD, PROD -> EXP, EXP -> TERM, etc, so that things can terminate.
Hope this helps!

Resources