4 ms·
I personally don't like Lisps, although I agree with you that when I learned them that emacs felt like the best editor to use (though I ended up using the Racke
by sreque 8y ago
I personally don't like Lisps, although I agree with you that when I learned them that emacs felt like the best editor to use (though I ended up using the Racket IDE for other reasons). To me, the biggest advantage of Lisps is that the syntax is so simple that building a macro system on top of the language is far simpler than doing so in other languages. Lisp has practically no syntax, so the macro system's complexity is much lower. Because the language's AST is simpler it is easier to deconstruct input syntax and generate output syntax.
Also, Lisps have no static type system, and for whatever reason static type aficionados have an aversion to macros or else want to make macros typed, and combining macros with type systems again makes macros far more complicated. One need only look at Scala's many attempts at adding macros to the language to see just how hard it is, and I personally have little expectation at this point that Scala will succeed in integrating macros into the language.
At the end of the day, the major selling points of Lisps are macros, and, for Schemes, baked-in delimited continuations. Most or all other features can be found in other languages in various forms.
- xfer 8y agoSome lisp have static type system, you talk about racket which has typed-racket. Also i don't think that static type aficionados want to make macros typed, since the output of macro-expansion phase goes into the type checker anyways; what people may want is control over errors.
- sreque 8y agoRacket is typed, but I don't think the macros themselves have types. Contrast that with both template Haskell and scala macros, both of which are typed and far more limited in what they can do. That said, it looks like OCaml macros are untyped, so perhaps it is just Haskell-influenced communities that generally look down on macro systems and want to subvert them under the of the type system.
- lispm 8y ago> Lisp has practically no syntax, That's not the case. You think of s-expressions as the syntax for Lisp, while s-expression is a data syntax. Lisp syntax is defined on top of s-expressions. Think about LET. It has syntax. LAMBDA: it has syntax. And so on. Most macros implement syntax. > Most or all other features can be found in other languages in various forms. It's not the amount of features, it's the integration which makes the character of a language.
- sreque 8y agoI implemented an R5RS macro expander, and, at least from the perspective of Scheme and macros, the only truly base is application, and all other forms can be reduced to it. For my expander I actually implemented all let forms, for instance, as macros that reduced to lambda applications. Now other lisps might have more forms that don't reduce quite nicely, I'm not sure, I still strongly believe in my original point that lisp practically has no syntax, and that's one of the reasons its easy to create macro systems for it.
- lispm 8y agoThat one can expand macros does not make them non-existing. The programmer writes the macro forms, not their expansions. If you actually look into the R5RS document, you can see that chapters 7.1.3-7.1.6 define the syntax for that particular toy version of Scheme. Lisp usually has three syntax types: function applications, built-in operators and macro operators. That you can implement some constructs by expanding them to LAMBDA expressions says nothing about the syntax of Scheme or Lisp. Lisp users don't develop in pure lambda calculus. Each built-in operator and each macro operator are adding syntax. One can reduce arithmetic to lambda expressions - this does not mean that Scheme has no arithmetic operators. R5RS documents arithmetic and not their lambda variant. Same as R5RS defines the syntax for DEFINE, COND, IF, CASE, SYNTAX-RULES, ... That's what the progammer sees, not LAMBDA. Take any real world Scheme, like Chicken Scheme -> lots of macros have added syntax. That's what the programmer uses, not lambda calculus.
- kazinator 8y agoWhat is your rewrite rule for reducing (set! var value) to application? For iteration and selection, did you just turn everything into lambdas? E.g. (if x y z) -> (__if_fun (lambda () x) (lambda () y) (lambda () z)) If you minimize the special forms, you have fewer cases in the expanding code walker; but then the compiler has little information for producing good code. Note that a compiler doesn't necessarily just let every instance of function application be function application. If the above expansion for if is forced upon you as a compiler writer, you can recognize the __if_fun function as a built-in and open-code it, effectively undoing the reduction to function application. Check that all arguments are lambdas (and diagnose if they aren't zero-argument lambdas) destructure them and turn into an open-coded branching construct. The cost for fewer code walking cases in the macro expander ends up being more cruft in the compiler. About let to lambda: in non-toy implementations, you almost always want to go the other way: recognize lambdas which can be turned into lets.