Recent from talks
Contribute something
Nothing was collected or created yet.
Polish notation
View on Wikipedia
Polish notation (PN), also known as normal Polish notation (NPN),[1] Łukasiewicz notation, Warsaw notation, Polish prefix notation, Eastern Notation or simply prefix notation, is a mathematical notation in which operators precede their operands, in contrast to the more common infix notation, in which operators are placed between operands, as well as reverse Polish notation (RPN), in which operators follow their operands. It does not need any parentheses as long as each operator has a fixed number of operands. The description "Polish" refers to the nationality of logician Jan Łukasiewicz,[2]: 24 [3]: 78 [4] who invented Polish notation in 1924.[5]: 367, Footnote 3 [6]: 180, Footnote 3
The term Polish notation is sometimes taken (as the opposite of infix notation) to also include reverse Polish notation.[7]
When Polish notation is used as a syntax for mathematical expressions by programming language interpreters, it is readily parsed into abstract syntax trees and can, in fact, define a one-to-one representation for the same. Because of this, Lisp (see below) and related programming languages define their entire syntax in prefix notation (and others use postfix notation).
History
[edit]A quotation from a paper by Jan Łukasiewicz in 1931[5]: 367, Footnote 3 [6]: 180, Footnote 3 states how the notation was invented:
I came upon the idea of a parenthesis-free notation in 1924. I used that notation for the first time in my article Łukasiewicz (1), p. 610, footnote.
The reference cited by Łukasiewicz, i.e., Łukasiewicz (1),[8] is apparently a lithographed report in Polish. The referring paper[5] by Łukasiewicz was reviewed by Henry A. Pogorzelski in the Journal of Symbolic Logic in 1965.[9] Heinrich Behmann, editor in 1924 of the article of Moses Schönfinkel,[10] already had the idea of eliminating parentheses in logic formulas. In one of his papers Łukasiewicz stated that his notation is the most compact and the first linearly written parentheses-free notation, but not the first one as Gottlob Frege proposed his parentheses-free Begriffsschrift notation in 1879 already.[11]
Alonzo Church mentions this notation in his classic book on mathematical logic as worthy of remark in notational systems even contrasted to Alfred Whitehead and Bertrand Russell's logical notational exposition and work in Principia Mathematica.[12]
In Łukasiewicz's 1951 book, Aristotle's Syllogistic from the Standpoint of Modern Formal Logic, he mentions that the principle of his notation was to write the functors before the arguments to avoid brackets and that he had employed his notation in his logical papers since 1929.[3]: 78 He then goes on to cite, as an example, a 1930 paper he wrote with Alfred Tarski on the sentential calculus.[13]
While no longer used much in logic,[14] Polish notation has since found a place in computer science.
Explanation
[edit]The expression for adding the numbers 1 and 2 is written in Polish notation as + 1 2 (prefix), rather than as 1 + 2 (infix). In more complex expressions, the operators still precede their operands, but the operands may themselves be expressions including again operators and their operands. For instance, the expression that would be written in conventional infix notation as
can be written in Polish notation as
Assuming a given arity of all involved operators (here the "−" denotes the binary operation of subtraction, not the unary function of sign-change), any well-formed prefix representation is unambiguous, and brackets within the prefix expression are unnecessary. As such, the above expression can be further simplified to
The processing of the product is deferred until its two operands are available (i.e., 5 minus 6, and 7). As with any notation, the innermost expressions are evaluated first, but in Polish notation this "innermost-ness" can be conveyed by the sequence of operators and operands rather than by bracketing.
In the conventional infix notation, parentheses are required to override the standard precedence rules, since, referring to the above example, moving them
or removing them
changes the meaning and the result of the expression. This version is written in Polish notation as
When dealing with non-commutative operations, like division or subtraction, it is necessary to coordinate the sequential arrangement of the operands with the definition of how the operator takes its arguments, i.e., from left to right. For example, ÷ 10 5, with 10 to the left of 5, has the meaning of 10 ÷ 5 (read as "divide 10 by 5"), or − 7 6, with 7 left to 6, has the meaning of 7 − 6 (read as "subtract from 7 the operand 6").
Evaluation algorithm
[edit]Prefix/postfix notation is especially popular for its innate ability to express the intended order of operations without the need for parentheses and other precedence rules, as are usually employed with infix notation. Instead, the notation uniquely indicates which operator to evaluate first. The operators are assumed to have a fixed arity each, and all necessary operands are assumed to be explicitly given. A valid prefix expression always starts with an operator and ends with an operand. Evaluation can either proceed from left to right, or in the opposite direction. Starting at the left, the input string, consisting of tokens denoting operators or operands, is pushed token for token on a stack, until the top entries of the stack contain the number of operands that fits to the top most operator (immediately beneath). This group of tokens at the stacktop (the last stacked operator and the according number of operands) is replaced by the result of executing the operator on these/this operand(s). Then the processing of the input continues in this manner. The rightmost operand in a valid prefix expression thus empties the stack, except for the result of evaluating the whole expression. When starting at the right, the pushing of tokens is performed similarly, just the evaluation is triggered by an operator, finding the appropriate number of operands that fits its arity already at the stacktop. Now the leftmost token of a valid prefix expression must be an operator, fitting to the number of operands in the stack, which again yields the result. As can be seen from the description, a push-down store with no capability of arbitrary stack inspection suffices to implement this parsing.
The above sketched stack manipulation works—with mirrored input—also for expressions in reverse Polish notation.
Polish notation for logic
[edit]The table below shows the core of Jan Łukasiewicz's notation in modern logic, which was also used, for instance, in Formal Logic by Arthur Prior.[15] Some letters in the Polish notation table stand for particular words in Polish, as shown:
| Concept | Conventional notation |
Polish notation |
Polish term |
|---|---|---|---|
| Negation | [16][2]: 27–28 | negacja | |
| Material conditional | [16][2]: 28–31 | implikacja | |
| Disjunction | [16][2]: 34–35 | alternatywa | |
| Conjunction | [16][2]: 35–36 | koniunkcja | |
| Non-conjunction | [16][2]: 36 | dysjunkcja | |
| Biconditional | [16][2]: 37 or [3]: 108 | ekwiwalencja | |
| Universal quantifier | [2]: 154–156 | kwantyfikator ogólny | |
| Existential quantifier | [2]: 157 | kwantyfikator szczegółowy | |
| Verum | [17]: 275 | prawda, prawdziwy | |
| Falsum | [17]: 275 | fałsz, fałszywy | |
| Possibility | [18]: 52 [3]: 134 or [19]: 111 | możliwość | |
| Necessity | [3]: 134 or [19]: 111 | konieczność |
The quantifiers ranged over propositional values in Łukasiewicz's work on many-valued logics.
Bocheński introduced a system of Polish notation that names all 16 binary connectives of classical propositional logic.[20]: 16 For classical propositional logic, it is a compatible extension of the notation of Łukasiewicz. But the notations are incompatible in the sense that Bocheński uses and (for nonimplication and converse nonimplication) in propositional logic and Łukasiewicz uses and in modal logic.
Implementations
[edit]Prefix notation has seen wide application in Lisp S-expressions, where the parentheses are required since the operators in the language are themselves data (first-class functions). Lisp functions may also be variadic. The Tcl programming language, much like Lisp also uses Polish notation through the mathop library. The Ambi[21] programming language uses Polish notation for arithmetic operations and program construction. LDAP filter syntax uses Polish prefix notation.[22]
Postfix notation is used in many stack-oriented programming languages like PostScript and Forth. CoffeeScript syntax also allows functions to be called using prefix notation, while still supporting the unary postfix syntax common in other languages.
The number of return values of an expression equals the difference between the number of operands in an expression and the total arity of the operators minus the total number of return values of the operators.
Polish notation, usually in postfix form, is the chosen notation of certain calculators, notably from Hewlett-Packard.[23] At a lower level, postfix operators are used by some stack machines such as the Burroughs large systems.
See also
[edit]References
[edit]- ^ Jorke, Günter; Lampe, Bernhard; Wengel, Norbert (1989). Arithmetische Algorithmen der Mikrorechentechnik [Arithmetic algorithms in microcomputers] (in German) (1 ed.). Berlin, Germany: VEB Verlag Technik. ISBN 3-34100515-3. EAN 978-3-34100515-6. MPN 5539165. License 201.370/4/89. Retrieved 2015-12-01.
- ^ a b c d e f g h i Łukasiewicz, Jan (1929). Elementy logiki matematycznej (in Polish) (1 ed.). Warsaw, Poland: Państwowe Wydawnictwo Naukowe; Łukasiewicz, Jan (1963). Elements of Mathematical Logic. Translated by Wojtasiewicz, Olgierd Adrian [in Polish]. New York, USA: The MacMillan Company.
- ^ a b c d e Łukasiewicz, Jan (1957) [1951]. Aristotle's Syllogistic from the Standpoint of Modern Formal Logic (2 ed.). Oxford University Press. (Reprinted by Garland Publishing in 1987, ISBN 0-8240-6924-2.)
- ^ Kennedy, John (August 1982). "RPN Perspective". PPC Calculator Journal. 9 (5). Mathematics Department, Santa Monica College, Santa Monica, California, USA: 26–29. CiteSeerX 10.1.1.90.6448. Archived from the original on 2022-07-01. Retrieved 2022-07-02. (12 pages)
- ^ a b c Łukasiewicz, Jan (1931). "Uwagi o aksjomacie Nicoda i 'dedukcji uogólniającej'" [Comments on Nicod's Axiom and on 'Generalizing Deduction']. Księga pamiątkowa Polskiego Towarzystwa Filozoficznego We Lwowie, 12. II. 1904–1912. II. 1929 (in Polish). Lwów: Wydawnictwo Polskie Towarzystwo Filozoficzne. pp. 366–383.
- ^ a b Łukasiewicz, Jan (1970). "Comments on Nicod's Axiom and on 'Generalizing Deduction'". In Borkowski, L. (ed.). Selected Works. Amsterdam and London/Warszawa: North-Holland Publishing Company/Polish Scientific Publishers. pp. 179–196.
- ^ Main, Michael (2006). Data structures and other objects using Java (3 ed.). Pearson PLC Addison-Wesley. p. 334. ISBN 978-0-321-37525-4.
- ^ Łukasiewicz, Jan (1929). "O znaczeniu i potrzebach logiki matematycznej". Nauka Polska (in Polish). 10: 604–620.
- ^ Pogorzelski, Henry Andrew (September 1965). "Reviewed work(s): Remarks on Nicod's Axiom and on "Generalizing Deduction" by Jan Łukasiewicz, Jerzy Słupecki, Państwowe Wydawnictwo Naukowe". The Journal of Symbolic Logic (Review). 30 (3). Association for Symbolic Logic: 376–377. JSTOR 2269644. (NB. The original 1931 paper "Uwagi o aksjomacie Nicoda i 'dedukcji uogólniającej" by Jan Łukasiewicz was re-published at Państwowe Wydawnictwo Naukowe (National Scientific Publishers), Warsaw, Poland in 1961 in a volume edited by Jerzy Słupecki.)
- ^ Schönfinkel, Moses (1924). "Über die Bausteine der mathematischen Logik" [On the building blocks of mathematical logic]. Mathematische Annalen (in German). 92 (3–4): 305–316. doi:10.1007/BF01448013. S2CID 118507515; van Heijenoort, Jean, ed. (1967). "On the building blocks of mathematical logic". A Source Book in Mathematical Logic, 1879–1931. Translated by Bauer-Mengelberg, Stefan [in Dutch]. Harvard University Press. pp. 355–366.
- ^ Gottschall, Christian (2005). Logische Notationen und deren Verarbeitung auf elektronischen Rechenanlagen aus theoretischer, praktischer und historischer Sicht (Diploma thesis) (in German). Vienna, Austria. p. 88:
Die ältesten Texte in den 'Selected Works', in denen Łukasiewicz polnische Notation verwendet, datieren relativ spät, sind aber Präsentationen vorangehender Arbeiten, die 'in the course of the years 1920–1930' (S. 131) stattgefunden haben, also auch keine genauere Zeitangabe geben.
{{cite book}}: CS1 maint: location missing publisher (link) - ^ Church, Alonzo (1944). Introduction to Mathematical Logic. Princeton, New Jersey, USA: Princeton University Press. p. 38.
[…] Worthy of remark is the parenthesis-free notation of Jan Łukasiewicz. In this the letters N, A, C, E, K are used in the roles of negation, disjunction, implication, equivalence, conjunction respectively. […]
- ^ Łukasiewicz, Jan; Tarski, Alfred (1930). "Untersuchungen über den Aussagenkalküls" [Investigations into the Sentential Calculus]. Comptes Rendus des Séances de la Société des Sciences et des Lettres de Varsovie (in German). 23 (Cl. III): 30–50.
- ^ Martínez Nava, Xóchitl (2011-06-01), "Mhy bib I fail logic? Dyslexia in the teaching of logic", in Blackburn, Patrick; van Ditmarsch, Hans; Manzano, Maria; Soler-Toscano, Fernando (eds.), Tools for Teaching Logic: Third International Congress, TICTTL 2011, Salamanca, Spain, 1–4 June 2011, Proceedings, Lecture Notes in Artificial Intelligence, vol. 6680, Springer Nature, pp. 162–169, doi:10.1007/978-3-642-21350-2_19, ISBN 978-3-64221349-6,
[…] Polish or prefix notation has come to disuse given the difficulty that using it implies. […]
- ^ A. N. Prior (1955). Formal Logic. Internet Archive.
- ^ a b c d e f Wolenski, Jan (1989). "Logic and Philosophy in the Lvov—Warsaw School". SpringerLink: 97. doi:10.1007/978-94-009-2581-6.
- ^ a b Łukasiewicz, Jan (1939). "Der Äquivalenzenkalkül". Collectanea Logica (in German). 1: 145–169.
- ^ Łukasiewicz, Jan (1930). "Untersuchungen über den Aussagenkalküls" [Investigations into the Sentential Calculus]. Comptes Rendus des Séances de la Société des Sciences et des Lettres de Varsovie (in German). 23 (Cl. III): 51–77.
- ^ a b Łukasiewicz, Jan (1953). "A System of Modal Logic". The Journal of Computing Systems. 3 (1): 111–149.
- ^ Bocheński, Józef Maria (1949). Written at Fribourg. Précis de logique mathématique (PDF). Collection Synthese (in French). Vol. 2. Bussum, Pays-Bas, Netherlands: F. G. Kroonder. Archived (PDF) from the original on 2023-08-03. Retrieved 2023-11-12. Translated as Bocheński, Józef Maria (1959). A Precis of Mathematical Logic. Translated by Bird, Otto A. [at Wikidata]. Dordrecht, Netherlands: D. Reidel Publishing Company.
- ^ "Google Code Archive - Long-term storage for Google Code Project Hosting". Archived from the original on 2017-09-28. Retrieved 2022-11-14.
- ^ "LDAP Filter Syntax". Archived from the original on 2022-10-14. Retrieved 2022-11-14.
- ^ "HP calculators - HP 35s RPN Mode" (PDF). Hewlett-Packard. Archived (PDF) from the original on 2022-01-21. Retrieved 2022-11-14.
Further reading
[edit]- Fothe, Michael; Wilke, Thomas, eds. (2015) [2014-11-14]. Written at Jena, Germany. Keller, Stack und automatisches Gedächtnis – eine Struktur mit Potenzial [Cellar, stack and automatic memory - a structure with potential] (PDF) (Tagungsband zum Kolloquium 14. November 2014 in Jena). GI Series: Lecture Notes in Informatics (LNI) – Thematics (in German). Vol. T-7. Bonn, Germany: Gesellschaft für Informatik (GI) / Köllen Druck + Verlag GmbH. ISBN 978-3-88579-426-4. ISSN 1614-3213. Archived (PDF) from the original on 2020-04-12. Retrieved 2020-04-12. [1] (77 pages)
- Langmaack, Hans [in German] (2015) [2014-11-14]. Written at Kiel, Germany. Friedrich L. Bauers und Klaus Samelsons Arbeiten in den 1950er-Jahren zur Einführung der Begriffe Kellerprinzip und Kellerautomat [Friedrich L. Bauer's and Klaus Samelson's works in the 1950s on the introduction of the terms cellar principle and cellar automaton] (PDF) (in German). Jena, Germany: Institut für Informatik, Christian-Albrechts-Universität zu Kiel. pp. 19–29. Archived (PDF) from the original on 2022-11-14. Retrieved 2022-11-14. (11 pages) (NB. Published in Fothe & Wilke.)
- Goos, Gerhard [in German] (2017-08-07). Geschichte der deutschsprachigen Informatik - Programmiersprachen und Übersetzerbau [History of informatics in German-speaking countries - Programming languages and compiler design] (PDF) (in German). Karlsruhe, Germany: Fakultät für Informatik, Karlsruhe Institute of Technology (KIT). Archived (PDF) from the original on 2022-05-19. Retrieved 2022-11-14. (11 pages)
External links
[edit]
Media related to Polish notation at Wikimedia Commons
Polish notation
View on GrokipediaInfix: p → (q ∧ r)
Polish: C p K q r
Infix: p → (q ∧ r)
Polish: C p K q r
Historical Development
Origins in Logic
Polish notation, also known as prefix notation, originated in the early 20th-century work of Polish logician Jan Łukasiewicz as a means to express logical propositions unambiguously without parentheses. Developed during the 1920s at the Lwów–Warsaw School of Logic—a prominent center for mathematical logic in Poland influenced by Kazimierz Twardowski—Łukasiewicz's innovation addressed the ambiguities inherent in traditional infix notations for logical connectives. This school emphasized rigorous formalization of logic, drawing inspiration from Aristotle's syllogistic reasoning and the need to systematize deductive processes in propositional logic.[5][6] Łukasiewicz first introduced the notation in his 1924 paper on the concept of implication, where he placed operators before their arguments to eliminate precedence issues and structural ambiguity. For instance, in infix form, expressions like negation (~P), conjunction (· P Q), or disjunction (v P Q) require parentheses for complex combinations to avoid misinterpretation, such as in (~P · Q) versus ~(P · Q). In Polish notation, these become prefix forms like Np for negation of P, K P Q for conjunction of P and Q, and A P Q for disjunction, allowing straightforward reading from left to right without additional symbols. This prefix placement ensured that every operator's scope was immediately clear, facilitating the formalization of deduction in a compact manner.[7][8] In the 1930s, Łukasiewicz extended the notation to handle multi-argument functions, further refining its applicability in propositional calculus and many-valued logics. These developments, building on his earlier work, supported the Lwów–Warsaw School's broader efforts to axiomatize logical systems and explore non-classical logics, such as three-valued logic for future contingents. The notation's design not only streamlined manual logical analysis but also laid foundational principles for unambiguous expression in formal reasoning.[5]Adoption in Computing
In the mid-20th century, Polish notation transitioned from its origins in mathematical logic to practical applications in computer science, particularly as a means to simplify expression parsing and evaluation in resource-constrained early computers. Researchers recognized that the prefix structure eliminated the need for parentheses and operator precedence rules, enabling unambiguous, linear processing of symbolic expressions without complex decoding logic. This made it appealing for both software interpreters and potential hardware designs during the 1940s and 1950s, when computing resources were limited and efficient parsing was critical for performance.[9] A seminal contribution came from Arthur W. Burks, Don W. Warren, and Jesse B. Wright in 1954, who analyzed a logical machine design incorporating parenthesis-free notation—equivalent to Polish prefix notation—to facilitate direct evaluation of logical formulas. Their work demonstrated how prefix notation allowed the machine to process expressions sequentially without recursive descent or auxiliary storage for grouping, reducing the complexity of the control unit and enabling stack-free evaluation through a simple scanning mechanism that applied operators to preceding operands. This exploration highlighted prefix notation's potential for hardware implementations, influencing discussions on instruction formats that minimized decoding overhead in prototype computers of the era.[10] The notation's influence extended to artificial intelligence and symbolic computation in the 1950s and 1960s, where it supported list-processing languages for manipulating complex expressions. John McCarthy, in developing Lisp starting in 1958, adopted a parenthesized variant of prefix notation—termed "Cambridge Polish"—to represent both programs and data uniformly as symbolic lists. This choice facilitated recursive evaluation and subexpression analysis, essential for AI tasks like theorem proving, by allowing the interpreter to immediately identify the primary operator and recurse on operands. Lisp's 1960 implementation as a prefix-based system marked a key milestone, embedding Polish notation in one of the earliest high-level languages for symbolic computation and inspiring subsequent AI research.[11][9]Fundamentals
Definition and Principles
Polish notation, also known as prefix notation or Łukasiewicz notation, is a system for expressing mathematical and logical expressions in which operators precede their operands, thereby removing the necessity for parentheses and explicit operator precedence rules. This notation ensures that every expression is unambiguous and can be parsed linearly from left to right, with the structure directly mirroring the hierarchical organization of operations.[7] The syntax of Polish notation defines expressions recursively: an atomic expression consists of a single variable or constant, while a compound expression begins with an operator symbol followed by a number of subexpressions equal to the operator's arity. For instance, a unary operator requires one subexpression, a binary operator requires two, and an n-ary operator requires n subexpressions, each of which must itself be a complete expression. This arity specification—unary for operations like negation, binary for addition or conjunction, and potentially higher for functions like summation—guarantees unique decomposition without ambiguity.[7] Semantically, Polish notation represents expressions as full binary trees (or more generally, ordered trees), where the root of each subtree is the operator and its children are the operands, providing a clear, parenthesization-free equivalent to infix notations. For example, the arithmetic expression , which equals under standard precedence, is written as in Polish notation. Similarly, in logic, the conjunction of propositions and the negation of is denoted , where is the binary conjunction operator and is the unary negation. These properties make Polish notation particularly suited for formal systems requiring precise, machine-readable representations.[7]Comparison to Other Notations
Polish notation, also known as prefix notation, places the operator before its operands, contrasting with infix notation where the operator is positioned between the operands, as in the expression 3 + 4 * 5, which requires parentheses and operator precedence rules to resolve ambiguity.[12] In Polish notation, the equivalent expression is written as + 3 * 4 5, eliminating the need for such rules and parentheses.[13] Postfix notation, or reverse Polish notation (RPN), positions the operator after its operands, as in 3 4 5 * +, and was proposed in 1954 by Arthur Burks, Don Warren, and Jesse Wright for use in early computer designs.[14] RPN facilitates straightforward stack-based evaluation by scanning from left to right but requires right-to-left reading for intuitive comprehension of expression hierarchy.[12] Key differences among these notations lie in their traversal order and parsing suitability: Polish notation supports left-to-right prefix evaluation, making it amenable to recursive descent parsing in top-down language implementations; infix notation prioritizes human readability despite its inherent ambiguity without precedence conventions; and postfix notation excels in stack-oriented processing but lacks hierarchical readability when scanned sequentially.[15][16] Conversions between these notations can be achieved through tree traversal methods on the expression's abstract syntax tree: preorder traversal yields Polish notation, inorder traversal produces infix (with adjustments for parentheses), and postorder traversal generates postfix.[16] The trade-offs of Polish notation include reduced parsing complexity in recursive programming languages due to its unambiguous, parenthesis-free structure, though it is less intuitive for human users compared to the familiar infix form.[7][12]Evaluation Methods
Core Algorithm
The core algorithm for evaluating Polish notation expressions employs a recursive procedure that processes the expression from left to right, exploiting its unambiguous prefix structure to avoid issues with operator precedence or parentheses. Upon encountering an atom (such as a numeric constant or variable), the algorithm simply returns its value. When an operator is encountered as the first element of a subexpression, the algorithm determines the operator's arity (number of required operands), recursively evaluates the immediately following subexpressions to obtain those operands, and then applies the operator to the results, yielding the subexpression's value. This method aligns with the evaluation semantics introduced in early computing systems for prefix forms, where expressions are treated as nested function applications.[17] The following pseudocode illustrates the standard recursive evaluation function, assuming the expression is represented as a list or array and that operator arities are predefined:function evaluate(expr, pos):
token = expr[pos]
if is_atom(token):
return get_value(token), pos + 1
else:
operator = token
[arity](/page/Arity) = get_arity(operator)
operands = []
current_pos = pos + 1
for i from 1 to [arity](/page/Arity):
operand_value, current_pos = evaluate(expr, current_pos)
operands.[append](/page/Append)(operand_value)
result = [apply](/page/Apply)(operator, operands)
return result, current_pos
function evaluate(expr, pos):
token = expr[pos]
if is_atom(token):
return get_value(token), pos + 1
else:
operator = token
[arity](/page/Arity) = get_arity(operator)
operands = []
current_pos = pos + 1
for i from 1 to [arity](/page/Arity):
operand_value, current_pos = evaluate(expr, current_pos)
operands.[append](/page/Append)(operand_value)
result = [apply](/page/Apply)(operator, operands)
return result, current_pos
expr, invoke evaluate(expr, 0) and verify that the returned position equals the expression length; the first return value is the overall result. This formulation mirrors the recursive eval function in symbolic expression processing systems, where special handling for atoms and recursive calls on argument lists ensures correct computation.[17]
The time complexity of this algorithm is O(n), where n is the number of tokens in the expression, as the recursion traverses each token exactly once in a single pass, with constant-time operations per token assuming fixed-arity operators.[18] Error handling is inherent in the recursion: arity mismatches are detected by insufficient subexpressions (failing to gather the required operands), while incomplete expressions are flagged if the final position does not reach the end of the input; such checks can raise exceptions or return error indicators during the recursive calls.[17]
This pure recursive approach assumes prior knowledge of the prefix structure, where operators precede all operands without ambiguity, and requires no explicit stack for evaluation—though an iterative stack-based variant exists for tail-recursion optimization or memory efficiency in deep expressions.[17]
Worked Examples
To illustrate the evaluation of Polish notation, consider the arithmetic expression , which corresponds to the infix form . The evaluation proceeds recursively from left to right, scanning the input sequence. The leading operator indicates a binary operation requiring two operands. The first operand is the atom 3. The second operand is the subexpression , which itself begins with the binary operator ; its operands are the atoms 4 and 5, yielding . Applying the outer operator gives . This recursive process can be visualized as a tree: the root node is with left child 3 and right child a subtree rooted at with children 4 and 5; evaluation traverses the tree depth-first, computing leaves first and propagating results upward. A more complex arithmetic example is , equivalent to infix . Scanning left to right, the leading requires two operands. The first is the subexpression , starting with binary ; its first operand is (binary with atoms 2 and 3, yielding 6), and its second is atom 4, so . The second operand for is atom 5. Thus, . The recursion depth here reaches three levels: innermost , then , then ; at each level, arity is resolved by consuming exactly two subexpressions or atoms per binary operator, assembling the result only after full operand evaluation. For a simple logical example, evaluate , where denotes disjunction (), conjunction (), and negation (); assume propositional atoms P, Q, R with truth values (true, true, false) for concreteness. The leading binary requires two operands. The first is atom P (true). The second is , a binary with first operand Q (true) and second (unary on R, yielding false, so false = true); thus, true true = true. Applying gives true true = true. The trace scans the input sequentially, recursing into subexpressions like (depth 1 under , depth 2 under ); results are assembled post-recursion, ensuring arity (unary for , binary for others) prevents premature application.[19] A common pitfall in evaluation is applying an operator before fully resolving its operands, such as mistaking in the first example as immediate without recursion, leading to incorrect partial results like treating 4 and 5 separately from the outer . Proper input scanning from left and strict recursion depth management avoids this by confirming complete subexpression consumption before returning.Applications in Logic
Representation of Formulas
In Polish notation, propositional logic formulas are structured by treating logical connectives as prefix operators that precede their operands, eliminating the need for parentheses through fixed arity conventions. Unary connectives such as negation are represented simply as the operator followed by the proposition, for example, N P for ¬P, where N denotes negation and P is a propositional variable.[3] Binary connectives like implication follow similarly, written as C P Q for P → Q, with C standing for implication and the operands P and Q placed after without additional grouping symbols.[3] For generality, connectives can extend to n-ary forms, allowing multi-place operators to apply to multiple arguments in sequence, as formalized in systems where the operator's arity determines the number of subformulas it governs.[20] This prefix structure extends naturally to predicate logic, where quantifiers function as unary prefix operators binding variables to subsequent formulas, such as A x P(x) for ∀x P(x), with A representing the universal quantifier and P(x) the predicate applied to variable x.[21] Function symbols in terms are likewise prefixed to their arguments, for instance, f x y for f(x, y), enabling nested compositions like g f x h y z for g(f(x), h(y, z)) without ambiguity.[21] Multi-place predicates integrate seamlessly, with the predicate symbol preceding its term arguments, maintaining the strict prefix order for all operators including relations like R x y for R(x, y).[20] The representation aligns with formula trees, where Polish notation corresponds to a preorder traversal of the syntax tree: the root node (main operator or connective) is written first, followed recursively by the traversals of its subtrees in left-to-right order.[22] This traversal method inherently avoids ambiguity in nested scopes, as the fixed arity of each operator dictates the partitioning of the sequence into subformulas, ensuring unique parsing without precedence rules or delimiters.[20] Jan Łukasiewicz's original system enforced a strict prefix format for all operators, including multi-place predicates and connectives, as introduced in his work on three-valued logic to facilitate compact, linear expression of complex formulas.[3] For example, the principle of non-contradiction ¬(P ∧ ¬P) appears as N K P N P, with K for conjunction.[3] Conversion from infix notation to Polish notation involves systematic prefixing while preserving the formula's truth-conditional structure: recursively convert subformulas, then place the main operator before the sequence of converted operands, adjusting for operator arity to maintain equivalence.[20] For instance, the infix (P → (Q ∧ R)) becomes C P K Q R, ensuring the implication's scope over the conjunction is retained through prefix ordering.[22]Benefits for Reasoning
Polish notation's prefix structure ensures complete unambiguity in formula representation, eliminating parsing disputes that arise from operator precedence and parentheses in infix notations, which is particularly beneficial for complex logical proofs. This clarity facilitates automated theorem proving by allowing proofs to be modeled as unambiguous tree structures, such as D-terms using detachment operations, enabling efficient mechanized search and compression in systems like Prover9.[7][23] The notation's design supports ease of mechanization through its inherent recursive nature, where the leading symbol identifies the primary connective, and subformulas are processed recursively, lending itself to formal definitions of logical consequence and validity without additional disambiguation rules.[7] This recursive parsing also enables simple algorithmic checks for well-formedness, such as a counting procedure that verifies formula balance by tracking connective and variable occurrences.[7] Pedagogically, Polish notation reveals the hierarchical structure of logical arguments by explicitly prefixing operators, making the main connective and nested dependencies immediately apparent, which aids in teaching deductive processes and formula analysis once the initial learning curve is overcome.[7] Historically, the notation enabled Jan Łukasiewicz's axiomatizations of propositional logic and the development of three-valued logics without errors from precedence conventions, as seen in his 1924 and subsequent works where prefix forms streamlined the representation of multi-valued implications.[7][5] Despite these advantages, Polish notation is less intuitive for arguments resembling natural language, where infix forms align more closely with everyday expression, contributing to its limited adoption in broader logical discourse.[7]Practical Implementations
In Programming Languages
Polish notation, also known as prefix notation, forms the foundational syntax of the Lisp family of programming languages, introduced by John McCarthy in 1958 as a means to represent both code and data uniformly through s-expressions.[11] In Lisp, expressions such as arithmetic operations are written with the operator preceding its operands, enclosed in parentheses, for example,(+ 1 (* 2 3)), which evaluates to 7.[24] This prefix structure enables homoiconicity, where code is treated as data, facilitating powerful macro systems that allow programmatic manipulation of source code during compilation or evaluation.[11]
Dialects of Lisp, such as Scheme and Clojure, have retained this prefix notation as their core syntactic form, preserving the uniformity that supports metaprogramming and extensibility.[25] Scheme, developed in the 1970s, uses fully parenthesized prefix expressions to define procedures and handle higher-order functions seamlessly.[25] Similarly, Clojure, a modern Lisp dialect running on the Java Virtual Machine since 2007, employs prefix notation for all function applications, enhancing interoperability with host platforms while maintaining Lisp's expressive power.[26]
Historically, Polish notation has appeared in variants of ALGOL, particularly as an intermediate representation in compilers for ALGOL 60, where it simplified expression parsing and evaluation.[27] Prolog, a logic programming language from the 1970s, incorporates prefix operators for unary predicates and arithmetic, such as negation as \+ Goal, aligning with its term-based syntax for rule definitions.[28]
In functional programming paradigms, prefix notation synergizes with concepts like currying and higher-order functions by treating all operators uniformly as function calls, allowing partial application and composition without special precedence rules.[29] This uniformity simplifies the implementation of abstractions, as functions can be passed and returned like any data, promoting concise expressions for complex computations.
Modern domain-specific languages, such as Wolfram Mathematica introduced in 1988, utilize prefix forms for mathematical expressions, exemplified by Plus[1, Times[2, 3]], which supports both symbolic computation and numerical evaluation in a consistent manner.
Despite these advantages, the prefix notation in Lisp variants has faced challenges regarding human readability, primarily due to dense parenthesization and the need to scan left-to-right for operator placement, prompting extensions like infix operator definitions in Common Lisp via reader macros or libraries such as Readable.[30]
Stack-Based Processing
Polish notation, also known as prefix notation, can be evaluated using an iterative stack-based algorithm that processes the expression without recursion. The method scans the expression from right to left, pushing operand atoms onto a stack and, upon encountering an operator, popping the required number of operands (typically two for binary operators), applying the operation, and pushing the result back onto the stack.[13] This approach ensures unambiguous evaluation by handling operator precedence inherently through the notation's structure.[31] The following pseudocode illustrates the core iterative algorithm for a binary operator expression in Polish notation:initialize empty stack S
scan tokens from right to left in the expression
for each token:
if token is [operand](/page/Operand):
push token to S
else if token is binary operator:
pop left_operand from S
pop right_operand from S
result = apply operator to left_operand and right_operand
push result to S
return top of S (the final result)
initialize empty stack S
scan tokens from right to left in the expression
for each token:
if token is [operand](/page/Operand):
push token to S
else if token is binary operator:
pop left_operand from S
pop right_operand from S
result = apply operator to left_operand and right_operand
push result to S
return top of S (the final result)
+ 2 3 (equivalent to 2 + 3) involves pushing 3, then 2, popping 2 (left) and 3 (right), computing 5, and pushing it as the result.[32]
This iterative method offers advantages over recursive evaluation, particularly for deeply nested expressions, as it avoids potential recursion depth limits in programming environments while maintaining linear time complexity O(n) where n is the expression length.[33] Space usage is O(n) in the worst case for the stack to hold intermediate results, but requires only constant additional space beyond the stack itself.[13]
A common variant adapts the algorithm for reverse Polish notation (postfix), which scans left to right instead: operands are pushed, and operators pop the right operand first followed by the left, reflecting the notation's operand-operator order.[13] The key difference for prefix scanning lies in the reversed traversal direction, which aligns operator discovery after its operands have been buffered on the stack.
Stack-based processing of Polish notation finds practical use in compilers for parsing mathematical expressions during code generation and in interpreters for efficient runtime evaluation of formulas, where the stack manages intermediate computations seamlessly.[33]