> After getting comfortable reading code with so many parentheses I never managed to get over the (). Ruby has a very flexible syntax, compared to many other languages, in that you can omit syntax in many cases. For instance, using () for method calls is largely, for the most part, optional. So when I have the python code: cat = Cat() cat.meow() I find it worse than the ruby code: cat = Cat.new cat.meow (Though you c…
> the ruby code: ``` cat = Cat.new cat.meow ``` As a non-Ruby user, this confuses me. Why can't `Cat.new` be a function reference? Does Ruby explicitly disallow this (i.e. passing around a function)?
A road to Lisp: Why Lisp
261–270 of 322 posts
Re: A road to Lisp: Why Lisp
#262Personally, I grew beyond this. I tried Common Lisp, Forth and Haskell. I enjoyed books On Lisp and Let Over Lambda. Now I think the best programming language is Barry Jay's Triage Calculus, which is close to combinatory logic or untyped lambda calculus. But unlike lambda calculus (which is easily expressed in TC), triage calculus has a built-in quoting and introspection (similar to Lisp's CAR and CDR), which lets yo…
Re: A road to Lisp: Why Lisp
#263Earlier quoted context omitted.
And it remains in a state of almost getting to the point of generic collections (like C++, Clojure, many others) using the standard functions, but not quite getting there. There are functions (not generic functions) which operate on sequences, but no standard way to extend what types are considered sequences (as one example). It makes sense that the 1995 version of the spec would be incremental, but without a further…
I don't quite understand what you mean by generic collections in this case. Do you want to restrict a list to only contain one specific type?
https://www.lispworks.com/documentation/HyperSpec/Body/17_a....
None of the functions operating on sequences are generic, so you cannot create your own type and do a `defmethod` and have them automatically adapt to it. And unlike `print-object` which gets used by format and print and others, there's also no "protocol" (or whatever term you like) generic function you can implement which will make your collection acceptable as a sequence.
You could build something like this, and maybe shadow the standard functions so that it's not a new set of functions from a user perspective, but it's a notable absence in a language with a rich OO system through CLOS. It makes sense that it wasn't in the original spec, but I still think it would have been something that would have been added if the development of CL (as a standard) had continued.
Re: A road to Lisp: Why Lisp
#264Re: A road to Lisp: Why Lisp
#265Earlier quoted context omitted.
> Homoiconicity doesn't give you anything special if your language can parse itself and can eval code. It just makes these completely abstract implementations simpler. Well, in a way it does give you something: By making expression of things like macros simpler, it makes them sometimes worthwhile, and makes it a reasonable request to have this kind of meta programming in your language at all. Without homoiconicity su…
I mentioned in other comment that homoiconicity doesn't necessarily make writing macros simpler. It makes writing trivial toy examples simpler. But let's compare it to a modern macro system like rust's or scala's, where you get a typed object representation of the AST, and for anything non-trivial you are better off with this latter. Also, arguably the best is to have certain features in the language itself, that can…
I don't agree, because that would mean, that the language must be huge, or grow huge over time, or alternatively be extremely abstract at its core, to be able to fit every use-case. Furthermore, so far I have not seen a language, in which the language designers managed to pull it off, so I tend to think that what already has been successfully pulled off, which is macros for language extensions, is the way to go.
Also this seems to be arguing from a limiting idea about what macros do. Macros are not always the right solution for any problem, in fact often they are not, but there are things you simply cannot do otherwise (without syntactic clutter), like for example changing the order of evaluation.
I also don't agree with your point about only making toy examples easier to write. For example I have written macros for implementing new define forms, which allow to specify contracts for function arguments and return values, or a macro for automatically defining functions that communicate to API routes, based on the function name, which I used to implement a proof of concept docker client for Scheme. Those are not toy examples, but real world applications, where a small macro can have big effect.
If you think macros need to be big and elaborate and complicated and otherwise are toys, then you don't really understand the power of macros. One of my favorite macros is the following threading macro:
(define-syntax ->
(syntax-rules ()
[(-> expr) expr]
[(-> expr* ... (op args* ...))
(op args* ... (-> expr* ...))]
[(-> expr* ... op)
(op (-> expr* ...))]))
Small, but a great addition to the code, that improves readability in many places of the code. It doesn't have to be big or long, in order to not be a toy example, but actually be a useful macro.Re: A road to Lisp: Why Lisp
#266Earlier quoted context omitted.
You sweet, summer child, just so you know, I have existed for nearly half a century in this world where the larger part of it I have spent dealing in computing. I have seen and dealt with more programming languages (including Ruby) than you can count with your fingers and toes and that number keeps growing still. I'm not advocating for any particular language, runtime, framework or paradigm - do use whatever your hea…
Apparently you're not experienced enough to have used a Lisp that doesn't have a REPL, nor a non-Lisp that does have a good one. You obviously haven't implemented a Lisp either, because then you'd understand what homoiconicity actually gives you. And also how a REPL is implemented (since you wouldn't just get one for free, it's a tool to implement).
Re: A road to Lisp: Why Lisp
#267Programming is in tension between the Light Side and the Dark Side. The Light Side is about preventing the programmer from making mistakes: Get rid of go-tos! Add static types! Do not allow a bug to be expressible. The Dark Side is about giving power to the programmer: Macros? Obviously. Operator overloading? Self-modifying code? Multi-line reg-exps? Go to town! The Light Side knows programmers are flawed and imposes…
I'll paraphrase someone who commented on HN once (about dynamic vs static typing, IIRC): permissive languages are enablers for solo programmers, but you need more restrictive languages for team programming. This matches my experience because you don't chose who you work with. Skill level is uneven among the team. Less skilled co-workers will make mistakes that will have more consequences when the language is more per…
Even the most skilled engineers are going to make these mistakes sometimes. That's the whole point of more restrictive tooling, and why Rust has exploded.
Don't get me wrong. I love Lisp, and use it in some personal projects. But I wouldn't want to use it in must not fail scenarios unless those situations can wait for a human to fix the running image.
Re: A road to Lisp: Why Lisp
#268Personally, I grew beyond this. I tried Common Lisp, Forth and Haskell. I enjoyed books On Lisp and Let Over Lambda. Now I think the best programming language is Barry Jay's Triage Calculus, which is close to combinatory logic or untyped lambda calculus. But unlike lambda calculus (which is easily expressed in TC), triage calculus has a built-in quoting and introspection (similar to Lisp's CAR and CDR), which lets yo…
Do you mean Tree Calculus? https://treecalcul.us
Re: A road to Lisp: Why Lisp
#269Earlier quoted context omitted.
I don't quite understand what you mean by generic collections in this case. Do you want to restrict a list to only contain one specific type?
I wrote that quickly and should have edited it for clarity. What I meant was a new collection type that could be treated as a sequence. https://www.lispworks.com/documentation/HyperSpec/Body/17_a.... None of the functions operating on sequences are generic, so you cannot create your own type and do a `defmethod` and have them automatically adapt to it. And unlike `print-object` which gets used by format and print and…
Re: A road to Lisp: Why Lisp
#270[dead]
In this case, it actually runs deeper than this, there are structural issues which prevent them from being sound right from the beginning. It's the mere fact that the whole behavior of your DSL can be silently changed without touching the module it's defined in, or the file it's being imported into. A well-meaning junior, in a completely different department, can completely destroy your invariants in a completely unrelated part of the codebase. Whether by shadowing runtime functions, or a package-level collision that exists upstream. Even Scheme's hygienic macros don't actually solve this, they just make it less likely. At the point in which you have no behavioral guarantees of semantics, you do not have a safety mechanism at all.
> There is no 'evaluative indirection' because a macro is a _compiler_ and the underlying code can be extremely alien to the DSL semantics.
This is a trivial contradiction. That is precisely evaluative indirection. Yes, stacking multiple compilers on top of each other, especially when their semantics are non-isomorphic, is a massive burden of mental overhead. Given you already have this problem with the mapping between Lisp and binaries, adding even more complicated layers on top of it is a recipe for disaster. Particularly because: you are going to make mistakes in your logic. Macros provide no means to stop you from blowing your own leg off when writing them. That is not what they are designed for.
Finally, you cannot escape the awkwardness of the underlying metaprogramming system, you will always have to wrestle with quotation and quasiquotation. You have to define a DSL before you can use it.
Only at the point in which you treat and use Lisp like an unserious toy, rather than the powerful tool that it is, can the fantasy of "macros are a safety mechanism" begin to make sense.