There seems to be a pattern to languages such that a kind of "universal statement" keeps consistently appearing out of the fog. It may be a way to build new languages (and libraries) without having to build custom syntax. Here are a bunch of different representations of more or less the same thing:
// traditional foo(x, y, z, glob="nar", znag=74) // array [see footnote 1] foo[1] = x foo[2] = y foo[3] = z foo["glob"] = "nar" foo["znag"] = 74 // array alternative (dot syntax, some languages can do both) foo.1 = x foo.2 = y foo.3 = z foo.glob = "nar" foo.znag = 74 // markup <foo param1=x param2=y param3=z glob="nar" znag=74> // ess-expression (foo x y z (glob "nar") (znag 74)) // lisp-likeIt generally can be represented as a map DataStructure where numbers are used if a parameter is positional. For object orientation, such can have a "path" attribute.
In some languages, all parameters are potentially named (not positional integers), but they are matched by position if there are positional parameters in the call statement:
foo(3, "blah", 88); foo(3, zog=88, bar="blah"); // equivalent to prior function foo(nif, bar, zog) { ... }Thus, we can choose the most convenient for a particular usage. Non-required parameters can be given defaults. Here, only "bar" is required.
function foo(nif=7, bar, zog="new thing") { ... }If we want to allow for blocks, including custom blocks, then we can have a convention like this:
foo(a, b=7, block="x(1);y(2)"); // equivalent: foo(a, b=7) { x(1); y(2) }The curly-brace block is just a syntactical convenience.
Lisp?
Hmm...looks like JohnMcCarthy beat you to the punch by a few years.
Lisp is based on nested lists for statements, not maps. One merely emulates maps when needed. True, later dialects may have added named parameters as a syntactical element. The UniversalStatement is kind of a map version of EssExpressions. It's almost like XML, but with an Algol-family twist. I do believe SyntaxMatters, and Lisp needs some work there.
The advantage of UniversalStatement over EssExpressions is that U.S. can be syntactically represented in multiple ways, per above. Sometimes a list (positional) is the best syntax for the job, sometimes array/object-like (map) is, sometimes attribute-like (keywords), and sometimes a mix. (A decent editor would be able to cross-convert as needed.) Lisp's One-syntax-fits-all does not cut it.
As a UsefulLie, generally there are 4 representation "paradigms" (at least for type-lite languages):
Lisp may very well cover only one way (although our friends working on SweetExpressions may disagree with you there)...but if the goal is to be "universal", then shouldn't it follow that there be only one canonical way to represent things? --Alpheus
"Represent" needs some clarification. A universal (internal) structure is not necessarily the same as a universal representation. I'd like to have some options to represent the canonical structure that best fits a given situation for reasons already described. I'm not happy with the one-presentation-fits-all of Lisp. -t
Numbers Versus Names
Above it's assumed that each position is potentially index-able by an integer. An alternative is indexing by a name since even positional parameters have a variable name associated with them. It is possible to have both, perhaps as a different map, so as to be able to have an arbitrary number of parameters. For example, we may want to be able to create our own concatenate function that can take infinity parameters in theory:
myConcat("foo","bar","zog","aa","bb","cc","dd","etc") ... function myConcat() result = "" for i = 1 to length(args[i]) // for each parameter... result = result . args[i] // append to result end for return result end functionIf we allow such, we'd probably also want the option to tell it to limit the number of parameters to only those specified, or vice verse. (A more practical use for this type of ability would be to control the delimiter between parameters to avoid repetitious code.)
One annoying feature of typical named parameter implementations is that usage of Boolean switches can be common, but end up being somewhat verbose.
foo(a, b, featureC=true, featureF=true, featureJ=true, featureM=true)One thing I liked about ExBase syntax is that one could write thus:
foo a, b, featureC featureF featureJ featureMThat's easier and more natural to read most of the time and more compact. However, this syntax was only for the built-in commands, not user-defined ones. I'm not sure how to add such to typical languages. Perhaps something like:
foo(a, b, #featureC #featureF #featureJ #featureM)as an optional shortcut to the first example. Mixed could perhaps also be allowed:
foo(a, b, featureJ=true, #featureC #featureF #featureM)with the caveat that all the "shortcut" ones are at the end to avoid confusion. (A debatable rule.)
Maybe "falsies" could be specified with "!". For example, "!foo" is a shortcut for "foo=false". Contrast:
foo(a, b, featureC=true, featureG=false, featureJ=true, featureP=false) // current . foo(a, b, #featureC, !featureG, #featureJ, !featureP) // proposed . foo a, b, featureC featureG off featureJ featureP off // ExBase-style . foo a, b, featureC Not featureG featureJ Not featureP // speculative 1 . foo a, b, featureC, Not featureG, featureJ, Not featureP // speculative 2(Dots due to a Wiki FireFox-related spacing bug)
--top
Footnotes
[1] There is also the "tree array" such that one can do trunk.branch1.branch2.leaf or trunk["branch1"]["branch2"]["leaf"]. They are an alternative to nested lists, although usually do lack ordering.
[2] Tables are essentially a form of positional, at least in the current RDBMS tradition. (TableOrientedProgramming)
Confer: MagicContainer See Also: MaspBrainstorming
CategoryMetaprogramming, CategoryLisp, CategorySyntax