I am trying to understand which are the right steps to perform the following reduction following the normal order reduction. I cannot understand which is the correct order in which I should perform the reduction, and why, in this expression:
(λn.λs.λz.n s (sz)) (λs.λz.s z)
could you please help me out?
Note: this reduction can also be seen as the function successor
(λn.λs.λz.n s (sz))
applied to the Church numeral 1
(λs.λz.s z)
knowing that the number zero is represented as:
(λs.λz.z)
The normal, AKA leftmost-outermost, reduction order attempts to reduce the leftmost outermost subterms first.
Since you are looking for the outermost terms, you need to determine the main building blocks of your term, remembering that every term is a variable, an abstraction over a term or an application of terms:
(λn.λs.λz.n s (s z)) (λs.λz.s z)
---------LHS-------- ----RHS----
----------APPLICATION-----------
The left-hand side (LHS) of the main term is the leftmost outermost one, so it is the starting point of the reduction. Its outermost abstraction is λn and there is a bound variable n in that term, so it will be substituted with the right-hand term:
λn.λs.λz.n s (s z)
-- -
However, since both LHS and RHS contain s and z variables, you need to rename them in one of them first; I chose to rename the ones in RHS:
λs.λz.s z -> λa.λb.a b
Now you can drop the λn abstraction and substitute the n variable with λa.λb.a b:
λn.λs.λz.n s (s z) -> λs.λz.(λa.λb.a b) s (s z)
-- - -----n-----
It's time to look for the next reduction spot:
λs.λz.(λa.λb.a b) s (s z)
Since lambda calculus is left-associative, this is the same as:
λs.λz.(((λa.λb.a b) s) (s z))
The next leftmost outermost reducible term is (λa.λb.a b) s which reduces to (λb.s b):
λs.λz.(((λa.λb.a b) s) (s z)) -> λs.λz.((λb.s b) (s z))
-- - - -
And the last reducible term is (λb.s b) (s z), where b is substituted with (s z):
λs.λz.((λb.s b) (s z)) -> λs.λz.(s (s z))
-- - ----- -----
Which leads to the final state in normal form:
λs.λz.s (s z)
Related
So I'm trying to define a function apply_C :: "('a multiset ⇒ 'a option) ⇒ 'a multiset ⇒ 'a multiset"
It takes in a function C that may convert an 'a multiset into a single element of type 'a. Here we assume that each element in the domain of C is pairwise mutually exclusive and not the empty multiset (I already have another function that checks these things). apply will also take another multiset inp. What I'd like the function to do is check if there is at least one element in the domain of C that is completely contained in inp. If this is the case, then perform a set difference inp - s where s is the element in the domain of C and add the element the (C s) into this resulting multiset. Afterwards, keep running the function until there are no more elements in the domain of C that are completely contained in the given inp multiset.
What I tried was the following:
fun apply_C :: "('a multiset ⇒ 'a option) ⇒ 'a multiset ⇒ 'a multiset" where
"apply_C C inp = (if ∃s ∈ (domain C). s ⊆# inp then apply_C C (add_mset (the (C s)) (inp - s)) else inp)"
However, I get this error:
Variable "s" occurs on right hand side only:
⋀C inp s.
apply_C C inp =
(if ∃s∈domain C. s ⊆# inp
then apply_C C
(add_mset (the (C s)) (inp - s))
else inp)
I have been thinking about this problem for days now, and I haven't been able to find a way to implement this functionality in Isabelle. Could I please have some help?
After thinking more about it, I don't believe there is a simple solutions for that Isabelle.
Do you need that?
I have not said why you want that. Maybe you can reduce your assumptions? Do you really need a function to calculate the result?
How to express the definition?
I would use an inductive predicate that express one step of rewriting and prove that the solution is unique. Something along:
context
fixes C :: ‹'a multiset ⇒ 'a option›
begin
inductive apply_CI where
‹apply_CI (M + M') (add_mset (the (C M)) M')›
if ‹M ∈ dom C›
context
assumes
distinct: ‹⋀a b. a ∈ dom C ⟹ b ∈ dom C ⟹ a ≠ b ⟹ a ∩# b = {#}› and
strictly_smaller: ‹⋀a b. a ∈ dom C ⟹ size a > 1›
begin
lemma apply_CI_determ:
assumes
‹apply_CI⇧*⇧* M M⇩1› and
‹apply_CI⇧*⇧* M M⇩2› and
‹⋀M⇩3. ¬apply_CI M⇩1 M⇩3›
‹⋀M⇩3. ¬apply_CI M⇩2 M⇩3›
shows ‹M⇩1 = M⇩2›
sorry
lemma apply_CI_smaller:
‹apply_CI M M' ⟹ size M' ≤ size M›
apply (induction rule: apply_CI.induct)
subgoal for M M'
using strictly_smaller[of M]
by auto
done
lemma wf_apply_CI:
‹wf {(x, y). apply_CI y x}›
(*trivial but very annoying because not enough useful lemmas on wf*)
sorry
end
end
I have no clue how to prove apply_CI_determ (no idea if the conditions I wrote down are sufficient or not), but I did spend much thinking about it.
After that you can define your definitions with:
definition apply_C where
‹apply_C M = (SOME M'. apply_CI⇧*⇧* M M' ∧ (∀M⇩3. ¬apply_CI M' M⇩3))›
and prove the property in your definition.
How to execute it
I don't see how to write an executable function on multisets directly. The problem you face is that one step of apply_C is nondeterministic.
If you can use lists instead of multisets, you get an order on the elements for free and you can use subseqs that gives you all possible subsets. Rewrite using the first element in subseqs that is in the domain of C. Iterate as long as there is any possible rewriting.
Link that to the inductive predicate to prove termination and that it calculates the right thing.
Remark that in general you cannot extract a list out of a multiset, but it is possible to do so in some cases (e.g., if you have a linorder over 'a).
I have a lemma telling that addition commutes:
Lemma commute: for all x y, add x y = add y x.
Now in my goal, I am trying to prove that:
add (add x (S y)) z = add x (S (add y z))
I would like to use my lemma to rewrite the inner add on the left
add x (S y) to add (S y) x.
However, the command rewrite commute instead rewrites the outer add:
add (add x (S y)) z to add z (add x (S y)).
Question: how to use commute for rewriting inner subexpressions?
You can precise which arguments you want for your lemma with :
rewrite commute with (x := x)(y :=(S y)).
But it is even more common to apply it like a function with :
rewrite (commute x (S y)).
If one of the specified arguments is obvious, you can avoid mentionning it in the first case, or put an underscore in the second, which would give here :
rewrite commute with (y :=(S y)).
and
rewrite (commute _ (S y)).
I just learned about lambda calculus and I'm having issues trying to reduce
(λx. (λy. y x) (λz. x z)) (λy. y y)
to its normal form. I get to (λy. y (λy. y y) (λz. (λy. y y) z) then get kind of lost. I don't know where to go from here, or if it's even correct.
(λx. (λy. y x) (λz. x z)) (λy. y y)
As #ymonad notes, one of the y parameters needs to be renamed to avoid capture (conflating different variables that only coincidentally share the same name). Here I rename the latter instance (using α-equivalence):
(λx. (λy. y x) (λz. x z)) (λm. m m)
Next step is to β-reduce. In this expression we can do so in one of two places: we can either reduce the outermost application (λx) or the inner application (λy). I'm going to do the latter, mostly on arbitrary whim / because I thought ahead a little bit and think it will result in shorter intermediate expressions:
(λx. (λz. x z) x) (λm. m m)
Still more β-reduction to do. Again I'm going to choose the inner expression because I can see where this is going, but it doesn't actually matter in this case, I'll get the same final answer regardless:
(λx. x x) (λm. m m)
Side note: these two lambda expressions (which are also known as the "Mockingbird" (as per Raymond Smullyan)) are actually α-equivalent, and the entire expression is the (in)famous Ω-combinator. If we ignore all that however, and apply another β-reduction:
(λm. m m) (λm. m m)
Ah, that's still β-reducible. Or is it? This expression is α-equivalent to the previous. Oh dear, we appear to have found ourselves stuck in an infinite loop, as is always possible in Turing-complete (or should we say Lambda-complete?) languages. One might denote this as our original expression equalling "bottom" (in Haskell parlance), denoted ⊥:
(λx. (λy. y x) (λz. x z)) (λy. y y) = ⊥
Is this a mistake? Well, some good LC theory to know is:
if an expression has a β-normal form, then it will be the same β-normal form no matter what order of reductions was used to reach it, and
if an expression has a β-normal form, then normal order evaluation is guaranteed to find it.
So what is normal order? In short, it is β-reducing the outermost expression at every step. Let's take this expression for another spin!
(λx. (λy. y x) (λz. x z)) (λm. m m)
(λy. y (λm. m m)) (λz. (λm. m m) z)
(λz. (λm. m m) z) (λm. m m)
(λm. m m) (λm. m m)
Darn. Looks like this expression has no normal form – it diverges (doesn't terminate).
Are there lambda terms M and B with M =/= B, so that M B and (M B) (M B) have the same canonical form?
Is a problem I encountered while I am still new with lambda calculus
I approached this
by having M = λx.x and B = λy.y
Μ Β = (λx.x) (λy.y) ->(β) λy.y
(M B) (M B) = ((λx.x) (λy.y)) ((λx.x) (λy.y)) ->(β) (λy.y) ((λx.x) (λy.y)) ->(β) (λx.x) (λy.y) ->(β) λy.y
and thus getting the same canonical form, but I am not confident that I am correct about (M B) (M B).
The reductions you have posted are correct.
One thing to know is that you can use any name for the bound variable in a lambda term, so the terms \x.x and \y.y are not really different; they are the same term. This is called alpha equivalence.
Another thing to know is that the function \x.x that just returns its argument is called the identity function, and is very useful to know.
Here is an answer to your question where M and B are different. M can be a function that ignores its argument and returns the identity function: \x.\y.y. B can be any term different from M.
Then,
(M B) -> \y.y
And also
((M B) (M B)) -> (\y.y \y.y) -> \y.y
I have a list of symbols which are organized by well formed parenthesis and I want to generate a tree like this one:
Leaf nodes are the symbols and the non-terminal nodes represent the parenthesis and I want to store in a strucuter both them.
Is there a way to build this tree?
It should be easy to split the whole formula into chunks that are direct descendants, while each chunk is well-formed. Use counting of nesting level for that: an opening parenthesis increases the level, a closing parenthesis decreases the level, and whenever the nesting level is 0, there is a boundary between chunks.
This way, you can convert
((a b) (c d)) e ((f g h) i)
into its constituent parts:
((a b) (c d))
e
((f g h) i)
For each part, if it contains more than one symbol, run the same algorithm recursively.
Certainly. First, if you implement a language in which parentheses are syntactic collecting punctuation (e.g. Python lists), you can likely use a built-in evaluation function to parse your input into a desirable structure.
Failing that ... I believe that the below is merely a more detailed version of the previous answer. The steps are simple (recursion should be simple, neh?):
If the input is atomic, make this a leaf node and return.
Split the given list into elements at every internal 0 in the open parenthesis count.
For each element in this list:
3a. Remove the outermost parentheses;
3b. Reduce the parenthesis counts by 1 each;
3c. Recur on this element.
Now, let's walk through the example you give.I'm ignoring the original root node text, in favor of the structure you show in the tree:
[(A ((B C) (D E)))(F G (H I L))]
At each level, the first thing to do is to strip off the outermost parentheses (actually brackets, in this case. I'm not sure why you have a different symbol on the outside).
(A ((B C) (D E)))(F G (H I L))
Now, start at the front, keeping count of how many open parentheses you have.
(A ((B C) (D E)))(F G (H I L))
1 23 2 3 2101 2 10
Note: If you need to throw syntax errors for an imbalance, you have a
nice check: the final count must be 0, with no following characters.
Wherever you have a 0 in the middle, break the string (marked with ^):
(A ((B C) (D E))) ^ (F G (H I L))
1 23 2 3 210 1 2 10
Now, recur on each element you found. If the element is atomic, it's a leaf node.
If you want to save counting time, carry the count as another argument to the routine. Reduce it by 1 on recursion.
^
A ((B C) (D E)) F G (H I L)
12 1 2 10 1 0
The left side has two elements: a leaf node A, and another expression on which we recur:
((B C) (D E))
12 1 2 10
There is no internal 0, so we trivially recur on the entire list:
(B C) (D E)
1 0 1 0
This break into two lists, (B C) and (D E)
Similarly, the right branch of the root node breaks into three elements: F, G, and (H I L). Handle these the same way.