<< Home |
Dmitri NosovickiWhy GOG?GOG allows to write concise and powerful programs that are easy to understand. As you will see, GOG expressions can be packed with meaning. But, perhaps, more important is that GOG allows closer investingation of alternative programming styles, which is absolutely required for people-centric experiments with programming languages. GOG provides:
Polynotational SemanticsThe idea of polynotational semantics is based on an observation that consecutive nature of written media limits the ways in which we can combine semantic units: variables can either follow the operator, or precede it, or be on both sides of it. This reduces possible number of basic notations, of which in widespread use are 3:
Each notation has its strengths, and GOG allows any of them. Importantly, GOG understands what you mean without additional syntactic clues. For example:
This reduces language syntax to just alphanumeric keys and LexemesLexemes modify meaning of functions. Similar semantic units are called
adverbs in tacit programming, Technically, Lexemes are just higher-order
functions that are promoted to a part of the language. Because of that you can
use lexemes with any expression that evaluates to a function, including lambdas
and subexpressions that return functions, for example:
@ = map; $ = apply; & = collect * Note that in the last example+ works as identity function.
Tacit function definitionInstead of
you can write
To distinguish lambda arguments from other names you start them with capital letters. You can use any notation inside lambdas, as well as nest lambda functions infinitely: Nested tacit definition
GOG understands as:
Asterisk at the start of Elem informs that it is a parameter of the inner lambda. The deeper inside resides your argument, the more asterisks you add. Note that List goes before Num in automatically created argument list. It is because auto-guessed lambda parameters are always assumed to follow alphabetic order. Example ProgramsSum square differenceFind the difference between the sum of the squares of the first one hundred natural numbers and the square of their sum, i. e. (1 + 2 + ... 100)^2 - (1^2 + 2^2 + ... 100^2) Prefix Notation:
Infix Notation:
Postfix Notation:
Explanation of the last line: Postfix notation passes single value from one
function to another, so every token must evaluate to a function of one
argument. Let's trace this expression: Let's take a closer look at the last function. It starts with Relation to ARC and LISP:In contrast to plenty of languages that allow to define words, there are few languages that allow to define syntax. Lisp is one of those few. Lisp's macros are a mechanism to extend any program with more or less custom syntax. But macros are ineffective at capturing small repetitive patterns. To illustrate, a call to macro takes 3+ characters, while better syntax is the one that saves one or two characters. That is why great macros can't fully undo ineffective core syntax. Lisp core syntax is notoriously limited. It features prefix notation -- a choice to simplify processing, not reading or writing. It can easily be proven that prefix notation is suboptimal for a number of programming idioms. But same can be proven for any other notation as well. Of course, the problem is not a particular notation, but that it is impossible to switch notations at will. In case of Lisp, the arbitrary choice in favor of one simple notation versus all others taints this otherwise perfectly symmetric language. GOG is an attempt at fixing that disproportion. GOG is based on ARC, which is a brilliantly clear, powerful and very practical functional language. As a result, GOG has all data types and features of Arc: macros, symbols, etc. You could safely say that most heavy lifting for GOG was made by its predecessors, and that GOG is just a continuation of Arc's ideas. Basically, GOG extends Arc with polynotational semantics, adds multivariable nested lamdas, and introduces a lexeme-based algebra for list operations. Furthermore, the initial idea was just to add polynotational semantics to arc as a patch. It worked, but soon appeared other features that were incompatible. Backward compatibilityGog is mostly backward compatible with the arc, in sense that traditional arc expressions are recognized as prefix notation, except the following cases:
Execution speedI did no optimization whatsoever, as I wanted to keep this highly experimental code as straightforward as possible. That said, the overhead is generally insignificant. First attempt to determine notation is made at compile time. That effectively minimizes run-time overhead, especially for prefix notation. Thus, during arc loading, 10839 of 10318 examined expressions (~95%) recognise as prefix notation at compile time. The rest requires run-time notation discovery, which should result in slight overhead for traditional expressions, and yet somewhat more substantial one for infix and postfix notations. Nevertheless, I was not able to notice any overhead using simple benchmarks. This topic might require further investigation, but, as far as I can see, the execution overhead is low. Precedence rulesIt would be a shame to introduce infix notation to a Lisp without precedence rules. GOG uses same precedence as C language does. New functions get precedence by association. Precedence order may be added or changed dynamically for any primitive at any time. See ac.scm comments for details, including on how to adjust the precedence order of any function. |
---|