Update 'stack language recursion' article to new math delimiters
Signedoffby: Danila Fedorin <danila.fedorin@gmail.com>
This commit is contained in:
parent
53ff0c39e4
commit
20d8b18a9b

@ 48,22 +48,22 @@ concrete syntax. How about something like:




Let's informally define the meanings of each of the described commands:




1. \\(\\text{Pop} \\; n\\): Removes the top \\(n\\) elements from the stack.


2. \\(\\text{Slide} \\; n \\): Removes the top \\(n\\) elements __after the first element on the stack__.


1. \(\text{Pop} \; n\): Removes the top \(n\) elements from the stack.


2. \(\text{Slide} \; n \): Removes the top \(n\) elements __after the first element on the stack__.


The first element is not removed.


2. \\(\\text{Offset} \\; n \\): Pushes an element from the stack onto the stack, again. When \\(n=0\\),


the top element is pushed, when \\(n=1\\), the second element is pushed, and so on.


3. \\(\\text{Eq}\\): Compares two numbers on top of the stack for equality. The numbers are removed,


2. \(\text{Offset} \; n \): Pushes an element from the stack onto the stack, again. When \(n=0\),


the top element is pushed, when \(n=1\), the second element is pushed, and so on.


3. \(\text{Eq}\): Compares two numbers on top of the stack for equality. The numbers are removed,


and replaced with a boolean indicating whether or not they are equal.


4. \\(\\text{PushI} \\; i \\): Pushes an integer \\(i\\) onto the stack.


5. \\(\\text{Add}\\): Adds two numbers on top of the stack. The two numbers are removed,


4. \(\text{PushI} \; i \): Pushes an integer \(i\) onto the stack.


5. \(\text{Add}\): Adds two numbers on top of the stack. The two numbers are removed,


and replaced with their sum.


6. \\(\\text{Mul}\\): Multiplies two numbers on top of the stack. The two numbers are removed,


6. \(\text{Mul}\): Multiplies two numbers on top of the stack. The two numbers are removed,


and replaced with their product.


7. \\(\\textbf{if}\\)/\\(\\textbf{else}\\): Runs the first list of commands if the boolean "true" is


7. \(\textbf{if}\)/\(\textbf{else}\): Runs the first list of commands if the boolean "true" is


on top of the stack, and the second list of commands if the boolean is "false".


8. \\(\\textbf{func}\\): pushes a function with the given commands onto the stack.


9. \\(\\text{Call}\\): calls the function at the top of the stack. The function is removed,


8. \(\textbf{func}\): pushes a function with the given commands onto the stack.


9. \(\text{Call}\): calls the function at the top of the stack. The function is removed,


and its body is then executed.




Great! Let's now write some dummy programs in our language (and switch to code blocks



@ 106,7 +106,7 @@ of all the computational chaos. We will adopt calling conventions.


When I say calling convention, I mean that every time we call a function, we do it in a


methodical way. There are many possible such methods, but I propose the following:




1. Since \\(\\text{Call}\\) requires that the function you're calling is at the top


1. Since \(\text{Call}\) requires that the function you're calling is at the top


of the stack, we stick with that.


2. If the function expects arguments, we push them on the stack right before the function. The


first argument of the function should be second from the top of the stack (i.e.,



@ 132,7 +132,7 @@ that it is called correctly, of course  it will receive an integer


on top of the stack. That may not, and likely will not, be the only thing on the stack.


However, to stick by convention 4, we pretend that the stack is empty, and that


trying to manipulate it will result in an error. So, we can start by imagining


an empty stack, with an integer \\(x\\) on top:


an empty stack, with an integer \(x\) on top:




{{< stack >}}


{{< stack_element >}}{{< /stack_element >}}



@ 141,7 +141,7 @@ an empty stack, with an integer \\(x\\) on top:


{{< stack_element >}}\(x\){{< /stack_element >}}


{{< /stack >}}




Then, \\(\\text{PushI} \\; 0\\) will push 0 onto the stack:


Then, \(\text{PushI} \; 0\) will push 0 onto the stack:




{{< stack >}}


{{< stack_element >}}{{< /stack_element >}}



@ 150,7 +150,7 @@ Then, \\(\\text{PushI} \\; 0\\) will push 0 onto the stack:


{{< stack_element >}}\(x\){{< /stack_element >}}


{{< /stack >}}




\\(\\text{Slide} \\; 1\\) will then remove the 1 element after the top element: \\(x\\).


\(\text{Slide} \; 1\) will then remove the 1 element after the top element: \(x\).


We end up with the following stack:




{{< stack >}}



@ 176,14 +176,14 @@ The function must be on top of the stack, as per the semantics of our language


(and, I suppose, convention 1). Because of this, we have to push it last.


It only takes one argument, which we push on the stack first (so that it ends up


below the function, as per convention 2). When both are pushed, we use


\\(\\text{Call}\\) to execute the function, which will proceed as we've seen above.


\(\text{Call}\) to execute the function, which will proceed as we've seen above.




### Get Ahold of Yourself!


How should a function call itself? The fact that functions reside on the stack,


and can therefore be manipulated in the same way as any stack elements. This


opens up an opportunity for us: we can pass the function as an argument


to itself! Then, when it needs to make a recursive call, all it must do


is \\(\\text{Offset}\\) itself onto the top of the stack, then \\(\\text{Call}\\),


is \(\text{Offset}\) itself onto the top of the stack, then \(\text{Call}\),


and voila!




Talk is great, of course, but talking doesn't give us any examples. Let's



@ 191,15 +191,15 @@ walk through an example of writing a recursive function this way. Let's


try [factorial](https://en.wikipedia.org/wiki/Factorial)!




The "easy" implementation of factorial is split into two cases:


the base case, when \\(0! = 1\\) is computed, and the recursive case,


in which we multiply the input number \\(n\\) by the result


of computing factorial for \\(n1\\). Accordingly, we will use


the \\(\\textbf{if}\\)/\\(\\text{else}\\) command. We will


the base case, when \(0! = 1\) is computed, and the recursive case,


in which we multiply the input number \(n\) by the result


of computing factorial for \(n1\). Accordingly, we will use


the \(\textbf{if}\)/\(\text{else}\) command. We will


make our function take two arguments, with the number input


as the first ("top") argument, and the function itself as


the second argument. Importantly, we do not want to destroy the input


number by running \\(\\text{Eq}\\) directly on it. Instead,


we first copy it using \\(\\text{Offset} \\; 0\\), then


number by running \(\text{Eq}\) directly on it. Instead,


we first copy it using \(\text{Offset} \; 0\), then


compare it to 0:




```



@ 218,7 +218,7 @@ on the stack:


{{< stack_element >}}factorial{{< /stack_element >}}


{{< /stack >}}




Then, \\(\\text{Offset} \\; 0\\) duplicates the first argument


Then, \(\text{Offset} \; 0\) duplicates the first argument


(the number):




{{< stack >}}



@ 237,7 +237,7 @@ Next, 0 is pushed onto the stack:


{{< stack_element >}}factorial{{< /stack_element >}}


{{< /stack >}}




Finally, \\(\\text{Eq}\\) performs the equality check:


Finally, \(\text{Eq}\) performs the equality check:




{{< stack >}}


{{< stack_element >}}{{< /stack_element >}}



@ 265,7 +265,7 @@ As before, we push the desired answer onto the stack:


{{< stack_element >}}factorial{{< /stack_element >}}


{{< /stack >}}




Then, to follow convention 3, we must get rid of the arguments. We do this by using \\(\\text{Slide}\\):


Then, to follow convention 3, we must get rid of the arguments. We do this by using \(\text{Slide}\):




{{< stack >}}


{{< stack_element >}}{{< /stack_element >}}



@ 274,7 +274,7 @@ Then, to follow convention 3, we must get rid of the arguments. We do this by us


{{< stack_element >}}1{{< /stack_element >}}


{{< /stack >}}




Great! The \\(\\textbf{if}\\) branch is now done, and we're left with the correct answer on the stack.


Great! The \(\textbf{if}\) branch is now done, and we're left with the correct answer on the stack.


Excellent!




It's the recursive case that's more interesting. To make the recursive call, we must carefully



@ 294,7 +294,7 @@ The result is as follows:


{{< stack_element >}}factorial{{< /stack_element >}}


{{< /stack >}}




Next, we must compute \\(n1\\). This is pretty standard stuff:


Next, we must compute \(n1\). This is pretty standard stuff:




```


Offset 1



@ 303,7 +303,7 @@ Add


```




Why these three instructions? Well, with the function now on the top of the stack, the number argument is somewhat


buried, and thus, we need to use \\(\\text{Offset} \\; 1\\) to get to it:


buried, and thus, we need to use \(\text{Offset} \; 1\) to get to it:




{{< stack >}}


{{< stack_element >}}\(n\){{< /stack_element >}}



@ 347,7 +347,7 @@ Call




If the function behaves as promised, this will remove the top 3 elements


from the stack. The top element, which is the function itself, will


be removed by the \\(\\text{Call}\\) operator. The two next two elements


be removed by the \(\text{Call}\) operator. The two next two elements


will be removed from the stack and replaced with the result of the function


as per convention 2. The rest of the stack will remain untouched as


per convention 4. We thus expect the stack to look as follows:



@ 368,7 +368,7 @@ Mul


Slide 1


```




The multiplication leaves us with \\(n(n1)! = n!\\) on top of the stack,


The multiplication leaves us with \(n(n1)! = n!\) on top of the stack,


and the function argument below it:




{{< stack >}}



@ 378,7 +378,7 @@ and the function argument below it:


{{< stack_element >}}factorial{{< /stack_element >}}


{{< /stack >}}




We then use \\(\\text{Slide}\\) so that only the factorial is on the


We then use \(\text{Slide}\) so that only the factorial is on the


stack, satisfying convention 3:




{{< stack >}}



@ 410,7 +410,7 @@ if {


}


```




We can now invoke this function to compute \\(5!\\) as follows:


We can now invoke this function to compute \(5!\) as follows:




```


func { ... }




Loading…
Reference in New Issue
Block a user