(and cond1
cond2
cond3)
(NB: multiple lines like this would really only be used for a lot of conditions or longer expressions.)We already do something similar with our algol-like languages:
if((cond1 || cond2) && (cond3 || cond4)
&& (cond5 || cond6)
&& (cond7 || cond8))
In lisp, CL at least, would look like: (if (and (or cond1 cond2)
(or cond3 cond4)
(or cond5 cond6)
(or cond7 cond8)) n P k = n! / (n - k)!
as the above? `n P k` will become something like `nperms n k`, factorial will be moved to prefix as `fact n / fact (n - k)`. We're already diverging from the domain language, there's no reason to consider a more logically consistent framework in this case than one that seems to have arbitrarily moved some things from infix to prefix, postfix almost universally to prefix, and left some infix as infix.SML allows you to have an infix function named "P", and Haskell allows something similar, although you have to quote it with backticks and can't use a capital letter to start a function name...
https://en.wikibooks.org/wiki/Standard_ML_Programming/Expres...
https://wiki.haskell.org/Infix_operator#Using_prefix_functio...
(FWIW Scala allows postfix operators, though you'd have to put the n! in brackets)
See Wolfram Mathematica for example.
Also, one of my usual DSL tricks is to allow arbitrary TeX in identifiers, which, combined with the literate programming tricks, allows to write very idiomatic mathematical expressions as a code.
There are ways to provide infix independently. That is to say, one person can develop this domain specific syntax, and another can develop or customize an infix engine for it.
In Common Lisp, there is a well known "infix.cl" module that provides mappings like a[b,c] -> (aref a b c), f(x, y) -> (f x y), a + b -> (+ a b) and so on.
This isn't understood as creating a new language as such; it's just a sugar. I think it allows new operators to be added with custom precedence and associativity. Or you can hack it however you want.
I've never seen it used in any production code.
The main purpose it serves is to satisfy people who want to know that it can be done; after that it turns out that they don't actually want it done. They just don't want to work with a language that can't do it.
The only program I'm aware of which actually supports writing mathematics that looks like the mathematics mathematicians write (the actual 2D notation) is Tilton's Algebra: written in Common Lisp.
The various mathematics languages out there fail.
Oh, and not to mention that mathematicians have been trained to work with this:
$\sin{(\frac{\pi}{2}-\theta)} = \cos{\theta}$
That's not such a bad example; I can still sort of see the trig identity in that if I squint my eyes.Mathematics isn't written with infix operators alone. Mathematics is written in a fancy 2d notation with all kinds of operator types: infix, prefix, postfix, around-fix, sub-fix, super-fix.
If you look at actual software for maths - several famous ones were written in Lisp like Macsyma, Reduce and Axiom - they provide more than infix.
And DSLs done the right way, via macros, are much better in integrating with tools than any ad hoc interpreted DSLs would ever be able to. You can easily have syntax and semantic highlighting infered, with auto indentation, intellisense and all the bells and whistles. For no extra cost.
No you can't. If the macro is arbitrary code then no tool can offer those things - there's no way to offer intellisense if you don't know what strings are meaningful in the language, and an unconstrained macro could use anything to mean anything.
Well, by that definition you get exactly the same if the host language of your DSL is statically typed and doesn't use macros. Custom syntax is custom syntax and whether tools/IDEs understand it has nothing to do with the host language.
Of course macro+syntax extension got absolutely nothing to do with what you can achieve in a language without macros.
And, no, you did not understand. Any custom syntax you're adding (if the right tools are used, like mine, for example) would automatically become available for your IDE and all the other tools, because they're reusing the same compiler front-end.
Just being able to execute the macro isn't enough for the IDE though. E.g. if a macro is "rot13 all identifiers in this block" then sure the IDE can run it, but it can't offer sensible autocompletion inside the block without understanding more about the structure of the macro.
But, yes, you cannot do it with the Common Lisp approach, where macros operate on bare lists, not the scheme-like syntax objects. The problem here is that the lists had been stripped from the important location metadata. For this reason I had to depart from the simple list-based macros and using custom syntax extension with rich ASTs underneath. Still, on top of a Lisp.
I agree that this is very rarely practically important - but if you think about it that's precisely the fact that a more restricted alternative to macros should be adequate.
EDIT: Which is obviously impossible if you assume a Turing Complete macro expansion language.
It's trivial. Any PEG parser I add on top automatically communicates all the highlighting, indentation data and all that to the tools (and it's inferred from the declarative spec, no additional user input is required). Underlying typing engines do the same, for the nice tooltips and code completion. The very compiler core doest the same with all the symbol definitions, dependencies, etc. Easy.
The way you express DSLs is something that needs to be understood by language tooling, so it belongs in the language spec.
So, in your rot13 example compiler would rat all the new identifiers with their origins to the tools.
How can the compiler know which identifier connects to which origin, unless because the macro complied with some standard/restriction/protocol? From a certain perspective all I'm suggesting is making these protocols part of the language standard - that is, define the DSL that's used to define DSLs, rather than allowing macros to consist of arbitrary code.
I've got some code published, but not that much in writing, planning to fix it some time later. See the stuff at my github account (username: combinatorylogic). Relevant things there are Packrat implementation, literate programming tools and an Emacs mode frontend.
It doesn't take much imagination.
You know how GNU Bash is customizeable with custom completion for any command, so that when you're, say, in the middle of a git command, it will complete on a branch name or whatever?
Similarly, we can teach a syntax highlighter, completer or whatever in some IDE how to work with our custom macro.
I expect that not that many C++ tools that do not use libclang will remain.
A good example of such a thing would be something like https://github.com/kframework/c-semantics
While you're technically correct, as a practical matter you won't implement a type system/type checker for all the DSLs you create. (Nor do I believe you'll even do it for anything approaching a majority.). Obviously, I'm using the impersonal "you" here.
Implementing real type systems is hard and mostly rather tedious work.
syntax-parse only gets you so far[1].
Maybe even have a series of examples that illustrate solutions you keep mentioning so others can learn and apply them. Just a thought. :)
If so, then I suppose I misunderstood you original claim, but I won't apologize because your claim was very opaque to anyone who doesn't know you.
[1] An example of what I mean would be xtext.
If you don't have a ready to use language construction framework targeting your meta-language, just build one. Easy.
As for typing specifically, the approach is rather fun and simple. Firstly, you'd need something like Prolog. It's really not that much, you can quickly build a passable implementation in just a couple of dozens of lines of code in pretty much any language. See miniKanren [2] for example. Then, any kind of typing is done easily: write a simple pass over your AST (may require some preparation passes, like resolving the lexical scope - but this is useful for all other things too), that will spit out Prolog equations for each expression node that needs typing. Then execute your Prolog code and get your types back. An implementation won't look any more complicated than a formal specification of a type system in a paper, using the type equations (as in [3]).
[1] https://github.com/combinatorylogic/mbase
[3] http://stackoverflow.com/questions/12532552/what-part-of-mil...
And then you'll get the most powerful programming environment possible - building arbitrarily complex hierarchies of languages, with a cost of adding a new language being close to zero, and with a free support from all your tools, for no extra cost.
Actually, while building such a hierarchy I naturally came to a number of "restrictions", although they're not enforced. I prefer to build compilers using chains of very trivial transforms, each implemented with at most a total language (or a simple term rewriting for most of the cases). It also helps to maintain a nice interaction with the tools.
That can only be true if your supposed "tree" actually contains loops. What language do you know of that generates cyclical parse structures?