Live data from Hacker News

Why Lisp?

blog.rongarret.info

141–150 of 248 posts

Re: Why Lisp?

#141

The article doesn't discuss macros, which is one of the answers to "Why Lisp?" I didn't "get" macros until I read a footnote in the (freely available) book Practical Common Lisp . In chapter 7, it introduces the `dolist` macro. DOLIST loops across the items of a list, executing the loop body with a variable holding the successive items of the list. This is the basic skeleton (leaving out some of the more esoteric opt…

It's kind of cool how in lisp you're supposed to do macros to change major aspects of how the language behaves, but in C if you try having a little bit of fun with #define and the pre-processor everybody starts getting just extremely rude at you.

To be fair, C #define macros are extremely dangerous and error prone in ways that Lisp macros aren't.

I haven't bought into this "Lisp macros are the best thing since sliced bread" idea, but without a doubt they are infinitely more awesome than C macros.

Re: Why Lisp?

#142

Earlier quoted context omitted.

It's true, as others have explained, that for many of the most common uses of macros, you can get the same effect with a higher-order function. But since macros operate at the syntax level, they can do things functions can't do. For example, they can generate and manipulate declarations. Say you're working with abstract syntax trees (assembly trees in a CAD app might be another example). These trees are built from no…

How's that different than what other languages call 'inheritance.'

Because most node classes have their own slots. Consider this example:

  class Node {...}
  class Expression extends Node {...}
  class Addition extends Expression {
    Expression left, Expression right;
    Set children() {
      return [a set containing 'left' and 'right'];
    }
  }
There's no way to write a single method 'children' on Node that will work for all its subclasses, because the method on Node can't access the subclasses' slots -- unless you use reflection, which is ugly and slow.

Re: Why Lisp?

#143
post #131
post #130

Earlier quoted context omitted.

So you think of a feature you'd like in your language. Let's consider the process you'd have to go through to use that feature. In most languages, you have to write the maintainers about the feature. You then have to convince them that the idea is good -- and this is by no means guaranteed; if they think your idea is bad, you're out of luck, and can never use the feature you'd like. Then someone has to implement it.…

Yes, I understand that argument, but I still find it unconvincing. Some features you just can't implement with macros, you need a change in the "substrate" (see kazinator's answer below). For the rest, I simply don't see how they are language-level features. They are just things you need for your project, in which case, why can't you simply implement them as a library? Even if you ignore the above, there's probably a…

Because macros let you control code in a way libraries don't^1.

Java now has this way to iterate over a collection of things:

    for(String exclamation: exclamations) {
        System.out.println("I yell " + exclamation + " at you");
    }
But this was only added in 2004!^2 So for almost 10 years, you had to manually iterate over stuff. How would you implement this as a library? Well, you could write a function that lets you write:

    iterate_over_collection(exclamations, function(collection) {
        System.out.println("I yell " + exclamation + " at you");
    }
But this is much uglier than the prior code. Also, it might not act the same. For example:

    int highest = ages[0];
    for(int age: ages) {
        highest = Math.max(highest, age);
    }
Would this work in a lambda? Well, if the language you're using has real closures, yes -- but does it? Do you know offhand? With a macro, your code will work.

> Even if you ignore the above, there's probably a good reason why the language designers don't want to approve your language-level feature. ... it can also be that you -- the applications programmer -- simply aren't well-versed in language design and can't think past your particular use case :) This wouldn't mean the feature is worthless (after all, you need it!)

That seems like evidence for my point -- macros let you build the language up for your own use case, not anyone else's. Without macros, your choices are "either everyone can use it, or no one can use it". Macros let you have a choice of "well, I can use it, even if no one else wants it, if I find it useful."

Macros can be viewed as libraries that act on the language itself. There isn't a difference between language-level features and "library functions" in a language with macros.

[1] Without getting into a Turing Tarpit. We're talking about using things in easy ways, not what is technically possible but ugly and kludgy.

[2] It was released in Java 5.0: http://www.java-tips.org/java-se-tips/java.lang/the-enhanced...

Re: Why Lisp?

#144

Earlier quoted context omitted.

Any real world problem solved in Lisp, relative to being solved in Python, eliminates the superfluous problem of Python being involved: a syntactically Fortran-like cumbersome scripting language with somewhat Lispy semantics. Note that you can program the CL system by expressing yourself in Python: https://common-lisp.net/project/clpython/ Common Lisp is not only a language, but also a platform (analogous to Mono or…

So your answer is 'I have no such example' ?

I think it would be pretty hard to write something like algo.monads in python when macros are not available.

https://github.com/clojure/algo.monads

Re: Why Lisp?

#145
post #140

Earlier quoted context omitted.

My favorite example for this is the lame idiom you see in Java code: if (log.isDebugEnabled()) { log.debug("expensive" + debug + message); } This is "better" than just log.debug(...) because with the latter, your expensive log message argument needs to be evaluated even if debug is disabled. However, in a language w/ macros, you just say: (debug (str "expensive" debug message)) and these considerations are already ta…

For completeness of the argument, this particular problem is solved in the Java world with string formats. With the slf4j interface, that would be: log.debug("expensive %s %s", debug, message) The message is not actually formatted into one string unless the DEBUG trace level is enabled. Of course, you are still passing the arguments around, but with object references that's a negligable difference. I still appreciate…

What if it's debug() instead of debug? That could be an expensive function that does a bunch of things to produce the debug output.

Re: Why Lisp?

#146
post #23
post #2

> The act of describing what you want the machine to do is interleaved with the machine actually doing what you have described, observing the results, and then changing the description of what you want the machine to do based on those observations. That sounds really powerful and interesting, but wondering how often is that used in practice? I can imagine maintaining and understanding a large self-modifying program l…

Like any powerful technology, Lisp's interactivity and dynamism can be used for good or it can be used for evil. Yes, it takes a little discipline to keep things from spinning wildly out of control. But it's well worth the effort.

Precisely. I find that getting the balance (that ethereal "style") right takes a lot more time than actually "learning" the language.

Re: Why Lisp?

#147
post #143
post #131

Earlier quoted context omitted.

Yes, I understand that argument, but I still find it unconvincing. Some features you just can't implement with macros, you need a change in the "substrate" (see kazinator's answer below). For the rest, I simply don't see how they are language-level features. They are just things you need for your project, in which case, why can't you simply implement them as a library? Even if you ignore the above, there's probably a…

Because macros let you control code in a way libraries don't^1. Java now has this way to iterate over a collection of things: for(String exclamation: exclamations) { System.out.println("I yell " + exclamation + " at you"); } But this was only added in 2004!^2 So for almost 10 years, you had to manually iterate over stuff. How would you implement this as a library? Well, you could write a function that lets you write:…

Agreed about your Java example. However, for the purpose of this discussion, let's assume we're talking about modern, well-designed languages without ugly kludges and with access to nice features such as lazy evaluation and real closures.

> Macros can be viewed as libraries that act on the language itself. There isn't a difference between language-level features and "library functions" in a language with macros.

I simply don't see why this is such a big deal. I need to see a real-world example (which, understandably, might be difficult to explain in a HN thread) of something that can be achieved with Lisp that is not reasonably achievable in elegant ways in other, non-Lisp modern languages. Again, let's assume we both understand the Turing Tarpit.

By the way, I don't want to sound dense. I understand some features you only "get" when you use them. What little I've seen of Lisp (Racket, actually) seemed very interesting! It's just that I can't get that enlightened moment where I see why Lisp macros are that important in the real world. This is important to me because macros are one of the key features Lispers use to try to convince other programmers Lisp is awesome. And I can see they are interesting and useful; I just fail to see why they are a such big deal that they set Lisp apart and that, for example, Paul Graham would call Lisp his "secret sauce".

Re: Why Lisp?

#148
post #140

Earlier quoted context omitted.

For completeness of the argument, this particular problem is solved in the Java world with string formats. With the slf4j interface, that would be: log.debug("expensive %s %s", debug, message) The message is not actually formatted into one string unless the DEBUG trace level is enabled. Of course, you are still passing the arguments around, but with object references that's a negligable difference. I still appreciate…

What if it's debug() instead of debug? That could be an expensive function that does a bunch of things to produce the debug output.

Solid point, that would be a downside of the slf4j approach.

Re: Why Lisp?

#149
post #60

Earlier quoted context omitted.

In my Lisp-esque language I use a temporary macro to automate the creation of some similar standard library procedures. This happens at runtime in the stdlib source file that is loaded: # Define procedures named int? float? etc that test the type of a value. (def def-type-predicate (mac (type-name) `(def ,(string-to-symbol (join "" $type-name "?")) (proc (x) (eq? (type x) ',type-name))))) (def-type-predicate int) (de…

Python you can do: def istype(i, t): return (type(i)==t) and istype(5, int) doesn't seem that much different than (int? 5) I bet there's a version in c++ with templates and typeid.

Yeah, I could do similar open testing:

    (def is-type (proc (x t) (eq? (type x) t)))

    (is-type 5 'int)
But it's nice to have single-parameter ones for FP list stuff. I suppose that 2-parameter version could have their order swapped and do partial application on top of it.

Anyway, was just sharing something I had fun making. No language wars intended.

Re: Why Lisp?

#150
post #132

Earlier quoted context omitted.

And then what would I need to type to write a log message?

You pass a lambda that returns the debug message. With javascripty syntax: debug( function(){ return "my expensive log message" }) BTW, if your language is lazily evaluated (like Haskell) then you don't need to do this because arguments will only ve evaluated when they are needed.

The downside there is you can still end up allocating a closure. Whereas an expanded macro shouldn't cost anything. (A sufficiently smart compiler might be able to optimize the closure allocation.)
Post reply on HN