Canadian Computing Competition: 2004 Stage 2, Day 1, Problem 3
You may be wondering what is the simplest computer we can create that can still perform
useful computation. Over the years, theoretical computer scientists have devised various
simple models of computation such as Turing machines and lambda calculus. In this problem,
we will see how we can perform arbitrary computation in an even simpler system devised in
1924 by Moses Schönfinkel, using just the letters
We can encode such a binary tree as a string in the following way. To represent a leaf
node, we write either
If the tree has the form of Figure 1(b), where
and are arbitrary subtrees, we replace it with only the subtree . In string form, if the string representation has the form , where and are the string representations of some arbitrary subtrees, we replace it with just .If the tree has the form of Figure 1(c), where
, , and are arbitrary subtrees, we replace it with the tree shown in Figure 1(d), which contains one copy each of and , and two copies of . In string form, we are replacing a string of the form with .If we cannot find any transformation to perform using any of the preceding rules, we recursively apply these transformation rules to the subtree rooted at the left child of the root.
If we cannot find any transformation to perform using any of the preceding rules, we recursively apply these transformation rules to the subtree rooted at the right child of the root.
If we cannot find any transformation to perform using any of the preceding rules, we print out the string representation of the resulting tree and stop.
How do we use these simple rules to perform computations? We can start by defining a
representation of natural numbers. Many representations are possible, but the following is
the most popular, devised by Alonzo Church. We will define zero to be
Notice that this has four occurrences of the subtree
For example, if we construct the tree
to make them look the same if they are equivalent. So, applying the transformation rules to
the tree
With a bit more playing around, we can come up with trees for other operations one might expect in a programming language, such as comparisons, conditionals, and recursion. These operators can be used to write more complicated programs. For example, the following tree computes factorials:
If we combine it with the normalization operator and the number
Input Specification
The input will consist of several strings representing trees, one tree on each line. No
input line will contain more than
Output Specification
For each line of input except the last blank line, your program must repeatedly apply the transformation rules to the given tree, until no further transformations are possible (rule 5). It must then print out, on a single line, the string representation of the resulting tree. Although for some trees, such as
it is possible to continue applying the rules forever, we will not include any such trees in the test data.
Sample Input
((KS)K)
((KK)S)
(((SK)S)K)
(((SS)K)S)
(((SK)K)K)
((((S((SK)K))(K(S((S(KS))K))))((S((S(KS))K))(K((SK)K))))((S((S(KS))K))(K((SK)K))))
(((S((S((SK)K))(K(S((S(KS))K)))))(K(K((SK)K))))(((S((S(KS))K))((SK)K))((S((S(KS))K))((SK)K))))
Sample Output
S
K
K
((SS)(KS))
K
((S((S(KS))K))((S((S(KS))K))(K((SK)K))))
((S((S(KS))K))((S((S(KS))K))((S((S(KS))K))((S((S(KS))K))(K((SK)K))))))
Comments