Live data from Hacker News

Why Lisp?

blog.rongarret.info

161–170 of 248 posts

Re: Why Lisp?

#161
post #147
post #143

Earlier quoted context omitted.

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 si…

One that helped some Java friends understand is passing blocks of code, but still having it look like just writing code. Imagine instead of try/catch/finally, a transaction/commit/rollback in Java:

transaction { // everything in here is in one transaction } commit { // do stuff if the commit is successful } rollback { // do stuff if we rollback }

All the try's and catch's can be stuff into the macro. It can be made to nest transactions within transactions.

For all practical purposes, you can't add that to Java. You'll always have to wrap up your transactions in boilerplate.

The Lisp equivalent of what I want, the resulting code would look like:

(transaction (do-stuff) (do-stuff-if-commit-successful) (do-stuff-if-rollback))

There are languages where I could define three blocks of code and pass them:

transaction(stuff, commit-stuff, rollback-stuff)

But that separates their definitions from their implementations.

How could you write the Lisp transaction expression in another language so that it looks like it's part of the language? (serious question, CL is the only language I use capable of being that close) Maybe I could torture Ruby to come close, but it would be far more difficult than the macro I had to write for Lisp.

Re: Why Lisp?

#162

Earlier quoted context omitted.

I agree. Macros are what made lisp, not parentheses. However, if we broaden the concept a little, we can do this type of macros for any language with a meta-layer such as MyDef. e.g. if you observe certain foreach pattern in Java, you can make a macro for that pattern and have the meta-layer look out and translate that for you (like having an automatic translator between you and javac. All you need is a scope type ma…

Macros are what made lisp, not parentheses. The parentheses are huge, though. It enables "Code is data" and "Data is code" in a powerful way. About Lisp, people always say "Macros are great" and "Code is data" and "Data is code", but it's hard to see what they mean without good examples. I mean, you can write code that writes code in any language that has a `print` statement. And obviously code is data, so what is th…

That's a great example right there.

Notice, the end result is just data, as terse and minimal as possible. But to act on (aka "interpret) that data, he wrote functions called "term", "part-of-speech" and "definition."

So now, that data is code. Code is data and data is code.

Re: Why Lisp?

#163

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…

Could someone please explain the difference between Lisp macros and, say, languages that have first-class functions? I get that a Lisp macro will be expanded into the respective code, while a function's execution is different. However, at the practical (i.e., developer's) level, are there any additional benefits? Can, say, a Lisp macro be 'partially formed', in the sense that it can expand into some boilerplate that…

Macros can provide a lot of syntactic convenience over those first-class functions, especially with heavily nested structures. For example, I can replace this monadic parser definition...

    function SpecDeclP()Parser{
      return Bind(SeqRight(MyKeywordP, IdentifierP), function(nm interface{})Parser{
        return Bind(BetweenParensP(IdentifierP), function(parm interface{})Parser{
          return Bind(SetSwitchUserStateP, function(_ interface{})Parser{
            return Bind(BlockP, function(bod interface{})Parser{
              return Result("func " + nm.(string) + "(" + parm.(string) + ")" + bod.(string))
            })
          })
        })
      })
    }
...with this more readable version if I have a recursively defined "macro" called doparse...

    doparse{
      nm   
This requirement arose in Haskell for its Parsec before it became a part of the syntax, then again later with the Arrow library which later also added it to the syntax. Whenever new abstractions are discovered/created, a macroing facility, whether for lisp-like syntax or some other, helps makes all the nested functions more readable.

Re: Why Lisp?

#164
post #75

Earlier quoted context omitted.

I don't think there are very many "real world" problems that you CAN solve in Lisp, and CANNOT solve in Python. Anything [0] you can write in Python, you can likely solve in Lisp, probably in similar line count (without macros). One thing I __really__ miss from working in lisp is the idea that I can reload things in the repl. In Python, once I've imported something, I can't really redefine it without pasting in the d…

ipython has a killer autoreload function: http://ipython.org/ipython-doc/stable/config/extensions/auto... In [1]: %load_ext autoreload In [2]: %autoreload 2 In [3]: from foo import some_function In [4]: some_function() Out[4]: 42 In [5]: # open foo.py in an editor and change some_function to return 43 In [6]: some_function() Out[6]: 43 It's nothing like a proper lisp repl, but you can sorta do this in vanilla python…

Thanks a TON! I am Frequently Slightly Annoyed by pressing control-. and having to re-import things, declare things, etc. I'm looking forward to using this.

Re: Why Lisp?

#165
post #117

Earlier quoted context omitted.

Do you know if the attaching to a remote instance is available in Racket? I spent some time learning racket a year or two ago, but was under the impression they took out some of the really cool features (or I never discovered them)

Not a racket user, but I'm almost certain that you can do this with Racket. Your editor doesn't care whether your REPL session is local/remote...it just connects to a an address/port. You can set this to be 127.0.0.1 or whatever remote server you want to connect to.

Most REPLs will only accept connections from localhost by default (a sensible idea). In this case you just need to setup an ssh tunnel to the machine and connect through that.

Re: Why Lisp?

#166
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…

It's not solved, because method arguments are evaluated eagerly. It means that message argument may not be an expensive expression, because it will be calculated independently whether debug is enabled or not. In case of macros arguments of this method could be evaluated lazily.

Re: Why Lisp?

#167

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…

Could someone please explain the difference between Lisp macros and, say, languages that have first-class functions? I get that a Lisp macro will be expanded into the respective code, while a function's execution is different. However, at the practical (i.e., developer's) level, are there any additional benefits? Can, say, a Lisp macro be 'partially formed', in the sense that it can expand into some boilerplate that…

You can support new paradigms, just as a library. For example, core.async was written as a macro. So Clojure basically got Go channels in a library, not a language upgrade.

Macros can fundamentally change code. Codewalkers. Back when OOP was a big thing (probably still is), Lisp programmers would probably amuse themselves by making object-oriented extensions to the language via macros, and sending them to each other.

This means that you are empowered, not just a language implementer. (First-class functions are important, and typically a better idea than "Guess I'll write my own macro!" but they only go so far.)

Re: Why Lisp?

#168
post #90

Earlier quoted context omitted.

Laziness can achieve a similar thing in that case (less elegantly, IMO), but there are other uses for macros that can't be solved with laziness.

Look at the uses for Template Haskell, for example. That's basically Haskell's macro system. And it's used quite a lot, though it's kind of arcane. If you want to create an abstraction that defines one or several data types, you'll think hard about whether you can use some kind of type-level programming instead—but if that's not possible, or not convenient, you can use TH macros. For example, the `lens` package defin…

using macros to deal with boilerplate, although useful, though is of a different order than things that simply cannot be expressed without macros

Re: Why Lisp?

#169

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…

Could someone please explain the difference between Lisp macros and, say, languages that have first-class functions? I get that a Lisp macro will be expanded into the respective code, while a function's execution is different. However, at the practical (i.e., developer's) level, are there any additional benefits? Can, say, a Lisp macro be 'partially formed', in the sense that it can expand into some boilerplate that…

Your question doesn't make sense. High order functions and macros are orthogonal concepts.

Lisp supports first-class, high order functions. In fact, it was probably the first language to do so.

Macros are different. And they're not just "expanded." Think of macros as full blown Lisp functions that run at compile time and generate new Lisp code, that is itself compiled at compile time. Since Lisp code is represented as Lisp's list data structure, it's super easy. The macro system does allow expansion/replacement (like C's preprocessor), but that's just scratching the surface.

Re: Why Lisp?

#170

Earlier quoted context omitted.

Macros are what made lisp, not parentheses. The parentheses are huge, though. It enables "Code is data" and "Data is code" in a powerful way. About Lisp, people always say "Macros are great" and "Code is data" and "Data is code", but it's hard to see what they mean without good examples. I mean, you can write code that writes code in any language that has a `print` statement. And obviously code is data, so what is th…

That's a great example right there. Notice, the end result is just data, as terse and minimal as possible. But to act on (aka "interpret) that data, he wrote functions called "term", "part-of-speech" and "definition." So now, that data is code . Code is data and data is code.

Agreed - that example is amazing. However, the devil's advocate in me can't help but ask: what if I want more than one transformation? What if I want to generate both HTML and, say, JSON for returning that information from a web service?

Hmm... it might work if I use some sort of global parameter: I first "execute the data" (damn!) with the output type set to HTML and then do it again with an output type of JSON.

Post reply on HN