I have now created three languages along the theme of "what would it be like if we made our programming languages aggressively simple?" and every time the answer has turned out to be "it would be very complicated" https://mastodon.social/@mcc/114365307342990008
@mcc the conclusion I arrived to in one of my talks on minimalism at FOSDEM is that programming tasks have an inherent complexity to them, and it can either be represented in the program source or not, in which case it is living in your head. In dynamically typed languages, you're still running a type checker in your head. In C, you're doing lifetime tracking in your head. We're always running the most complicated dependently-typed checker in our heads, if the problem itself needs it.
…it matters because *this specific experiment didn't work that way*. I've talked about this on here already but if this language sees a list in function position it just interprets it:
So I'm re-formulating my "0-LISP" experiment from the last couple months, in a kinda fundamental way. I think this makes it better / more likely to be someday useful, but it feels weird.
The original intent of this experiment was to make a language where code is a hygienic data structure:
- In TCL, strings are functions, because strings can be "eval"ed. - But strings are not a good data structure; when they break it's in unclean ways. - A solution: Go LISPy, use lists.
LISP and its descendants are "homoiconic" languages: The code model is represented within the data model. You can easily represent LISP code within LISP as quoted lists of symbols, you can(?) construct a function by constructing a list containing code and then pass that to defun (??) to make an executable function. I feel homoiconicity has lost some meaning with time, as modern languages like Go or Rust with (LISP-inspired!) macro systems only present a *representation* of code to other code.
An important thing about homiconicity: In homoiconic languages, you can build code in an in-memory structure, and there's some way to execute that structure, but that *doesn't mean the interpreter is literally executing the structure you built*. LISP has "defun", TCL has "proc". In each of these cases, you pass in a code structure (formally, at runtime) and get back an executable object. You execute these "compiled" executable objects, not the original data. This is a fiddly distinction, but…
@whitequark I think what worries me is that any intentional semantics for having a *specific known thing* happen when you edit a list mid-execution would both require amount of added complexity in the language spec to challenge the claim this is a "simple" language, and also might put awkward long-term restrictions on the implementation.