Prolog was weirdly simple to make, once you managed to grasp the concept in its wholeness. Yes I made one in 1982 in Osborne-1. I even managed to include all numbers in the machine into search space, meaning 0 to 0xFFFF -- which real Prologs do not do.
Annoying part of 8080 was that the command set had holes in it and mystery restrictions. Which were hard to remember. And 12 undefined opcodes. Z80 solved all that.
However, you had to be a programmer Anno Dominii 1975 to fully understand what heavenly Joy and Jubilation Z80 was.
8080 assembly language makes it easy to understand what the restrictions are. Z80 much less so.
Much of the instruction set was carried over from the 8008, that's where you get MOV & ALU operations, the pseudo-register M standing for memory at address HL, etc. The 8080 then added to that some extensions that weren't as orthogonal, but greatly improved the usability.
That memory copy example, rewritten for the 8008, would take more than 30 instructions, constantly juggling pointers in and out of HL, because there was absolutely no other way to access memory. For that you needed an extra free register as well (no XCHG instruction!), so only a single 8 bit register would be available to use as a counter. Or you could store the counter in memory, but in that case there would be even more instructions to first load the address of that variable into HL!
In 8080 assembly as defined by Intel, each of these extended instructions has a unique mnemonic. LDAX = load A extended, etc. There's a one-to-one correspondence with the opcodes, so it's easy to memorize the encoding (best in octal), and what register can be used for what purpose.
Zilog added even more unorthogonal extensions to this set, but "simplified" the assembly so that one mnemonic could produce many different opcodes, some with an additional prefix. Most of these don't provide any benefit over using the existing 8080 opcodes, and you have to memorize lots of seemingly arbitrary restrictions. If you first learn Z80, those make no sense at all.
And yes. There was 8080-assembler in PDP-11, but it was just regular PDP assembler with extra macroes. It did not know those forbidden commands and thus produced undefined opcodes with random and entertaining results.
Only allowed color: vomit-green. Strangely repulsive. I do not think this is experience induced, because I loved my green XB3-bicycle from Kharkov Bicycle Factory.
I want this. I have Wifi door lock too far away from base station. It was often stuck in a loop trying to connect to neighbours' Wifis. By try and error I managed to block those using metal foil, but it was hard work.
You do not need macros for anything. They are not the tool to "extend the language", but instructions for the compiler. And if the system does not even have a compiler, macros are useless, often incredibly stupid.
If you have an interpreter only, no compiler, using macros for metaprogramming anwyay at least prepares you for the eventuality that one day there will be a compiler. The macros will Just Work as before, only the expanded code is now processed by compiling.
Suppose you reject the idea that there will ever be a compiler. Macros are still useful for doing "compiler-like things" in the context of interpretation, like transforming code into something that will interpret better.
We can regard the interpreter as a virtual machine acting on a representation of the code; the macro system lets you manipulate the representation in a pre-computed pass, which has no further cost at run time.
If you have a code expansion pass on top of an interpreter, for supporting macros, you can use that as an excuse to perform built-in code transformations that are not macros; those enable you to have more flexibility in how special forms are implemented.
In TXR Lisp case is a macro (family) which performs certain optimizations like recognizing values in a range and emitting a table switch. This works interpreted or compiled:
It is faster to do some checks and interpret the sys:switch special form to dispatch by a numeric index than to do a large number of exhaustive comparisons.
Ultimately, the way we optimize interpretation is by compiling, but it can still be worth it to have better interpretation here and there.
You don't want to do this kind of optimization at run-time; you don't want the interpreter to be evaluating the condition "are these cases integers (or characters) in a tight range?". That's a property of the syntax in which the cases are constants; it wants to be pre-computed once.
TLDR, but you are (probably) describing somekind of builtin property.
I am just saying that the end-user do not need macros for much anything, unless she has some specific optimization in mind. Bloody annoying when they start making cryptic macros to "extend the language".
"Need" is a very tenuous word, because most of any tool stack consists of benefits.
End users benefit from things that they don't strictly need.
Once you start talking about what people don't need, it's hard to do it in a way such that they need Lisp but don't need macros.
Sometimes "need" is about dependencies; i.e. things you "need" are provided by upstreams; you stop needing things that you made yourself.
E.g. "I don't need objects. Because, well, I have lambdas and macros, and with that control over syntax and semantics, I made my own objects. So, strictly speaking, I do need objects, just don't need them from you or anyone else."
People disagree over what constitutes a benefit; something someone finds beneficial in their work is crap to someone else, and the easiest way to disparage someone else's beneficial thing is resort to the necessity rhetoric.
"Everything that I found beneficial in conducting my successful XYZ project, which got to a level of complexity and quality in so many years of effort and lines of code, was obviously necessary; all else is unnecessary."
A really sneaky way to do that is to repeatedly acknowledge the benefit of something while emphasizing the lack of necessity. With a sprinkle of FUD about possible harms that outweigh benefits ...
I really do not understand this whining and downvoting.
In so-called real life somebody has to live with the malformed macro, whose only purpose is to beautify the code.
I even made un-macrofier, which deleted all macros and replaced instances with macroexpand, because slight adjustement of code resulted mysterious errors cause by nasty macroes.
And lets not talk about Common Lisp loop macro, which was probably scooped up from latrine of hell by the Devil himself.
Nobody has to live with a malformed macro because they can just observe what code expansion it is performing and write their own which does it better. (Speaking of CL loop, some people have resorted to this solution of actually dragging an implementation of loop into their application, to avoid issues with a vendor's loop, or behavioral differences among different ones---yes, loop has this, unfortunately).
The malformed macro situation is a lot better than the situation of a malformed API function to which you don't have source code.
Anything that is formed can be malformed. DNA can be malformed, leading to malformed fingers someone actually has to live with; so let's not have fingers.
You can make random search N in the MP3-module, because OFF/ON restarts and then you short NEXT-button wires N times.
reply