Live data from Hacker News

Why Lisp?

blog.rongarret.info

61–70 of 248 posts

Re: Why Lisp?

#61

The interactive model is insanely cool. When building a toy game engine a while back ( https://github.com/orthecreedence/ghostie ) I saved probably half the development time by being able to redefine functions/values while the game was running . The old way of lisping is to prototype in lisp, then build in a "real" language (c/java). However nowadays the lisp implementations (CCL/SBCL specifically) are fast/advanced…

Even better you can attach the repl to a remote instance. I had a problem a little while ago that could only be reproduced on the server. I could connect to the repl over ssh and evaluate and modify code directly.

Compare that to a similar problem I had with a C# app we had. For that I had to stick in a load of logging code, check it in then wait half an hour for the CI server to deploy before running and checking the logs.

Working with a Lisp was much more pleasurable.

Re: Why Lisp?

#63

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…

TXR Lisp is completely strictly evaluated, like many other Lisp dialects. Function argument expressions are reduced to their values, in left to right order. Then the application of the resulting values to the function takes place.

Yet, with macros I have this:

  ./txr -p '(mlet ((x (lcons 1 x))) x)'
  (1 1 1 1 1 1 1 1 1 ... nonterminating sequence of 1's ...
This created a circular list!

The special mlet ("magic let" or "mutual let") construct has allowed the expression which initializes s, (lcons 1 x), to refer to x.

This works because both mlet and lcons are macros. The lcons macro (rather, the code generated by the macro!) returns a lazy cons cell, without immediately evaluating its arguments 1 and x. In the case of x, this is a damn good thing because x is not yet initialized! When the lazy cons is accessed (when the list object is printed), the evaluation of x takes place. By that time, x holds the lazy cons cell, and since the variable x is in scope of the argument x in (lcons 1 x), the lazy cons is able to force, setting its CDR field back to itself, creating not a lazy list, but a circular list.

With lcons, I we can make a fibonacci function quite similarly to how you might do it in Haskell:

   (defun fib2 (a b)
     (lcons a (fib2 b (+ a b))))
We call this as (fib 1 1) and it gives us a lazy list.

Here, we have a marriage between a lazy data structure and a macro. Without lazy conses, the lcons macro would have no target language to expand into. Without the lcons macro, lazy conses can't be used in the above convenient way; we would have to write fib2 in terms of the macro expansion:

  $ ./txr -p "(sys:expand '(defun fib2 (a b)
                             (lcons a (fib2 b (+ a b)))))"
(defun fib2 (a b) (make-lazy-cons (lambda (#:lcons-0001) (rplaca #:lcons-0001 a) (rplacd #:lcons-0001 (fib2 b (+ a b))))))

The circular list mlet, when fully expanded looks like this, by the way:

  $ ./txr -p "(sys:expand '(mlet ((x (lcons 1 x))) x))"
  (let (#:g0001) (sys:setq #:g0001 (cons 'sys:promise
  (cons (lambda () (make-lazy-cons (lambda (#:lcons-0046)
  (rplaca #:lcons-0046 1)
  (rplacd #:lcons-0046 (force #:g0001))))) '(delay (lcons 1 x))))) (force #:g0001))
It's a gritty oat-meal of delays, lambdas, forces, and cons manipulation. One thing that is conspicuously absent amid the toenail clippings: what happened to the x variable? Haha!

Re: Why Lisp?

#64

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…

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 taken care of for you:

https://github.com/clojure/tools.logging/blob/master/src/mai...

Re: Why Lisp?

#65

There are certainly good reasons why lisp is the way it is. I dislike reading that style of code, though. I don't like how you have to read it in a strange sort of top-to-bottom-but-also-inside-out way (really this happens in all languages but it's especially bad in lisp because there are no infix operators and so forth), and of course the common gripe about all the parens. And to be honest, I am not really intereste…

Clojure has a threading macro built in (http://clojuredocs.org/clojure.core/-%3E) which lets you write code like :

    user=> (-> "a b c d" 
               .toUpperCase 
               (.replace "A" "X") 
               (.split " ") 
               first)
It is trivial to write the macro in other Lisps.

Re: Why Lisp?

#66

The interactive model is insanely cool. When building a toy game engine a while back ( https://github.com/orthecreedence/ghostie ) I saved probably half the development time by being able to redefine functions/values while the game was running . The old way of lisping is to prototype in lisp, then build in a "real" language (c/java). However nowadays the lisp implementations (CCL/SBCL specifically) are fast/advanced…

What sort of tools are required for this? I'd like to start taking Lisp seriously, but workflow stories like this tend to hinge on using Emacs/SLIME. Is that always the case? EDIT: I suppose what I'm asking is whether you could elaborate more on what this looks like, in practice.

I use vim with "vim-slime", which is different than "slimv". https://github.com/jpalardy/vim-slime

Basically I have a horizontally split 'screen' session, code in the top and repl in the bottom, and I just ctrl+[c+c] to send paragraphs from the top to the bottom. I don't remember if vim-slime comes with it or if I augmented it, but I also do ctrl+[c+f] to send the current Lisp/Clojure form, ctrl+[c+l] to send the current line... Or just ctrl+a+tab to switch screen windows and type in the REPL directly.

Re: Why Lisp?

#67

The interactive model is insanely cool. When building a toy game engine a while back ( https://github.com/orthecreedence/ghostie ) I saved probably half the development time by being able to redefine functions/values while the game was running . The old way of lisping is to prototype in lisp, then build in a "real" language (c/java). However nowadays the lisp implementations (CCL/SBCL specifically) are fast/advanced…

What sort of tools are required for this? I'd like to start taking Lisp seriously, but workflow stories like this tend to hinge on using Emacs/SLIME. Is that always the case? EDIT: I suppose what I'm asking is whether you could elaborate more on what this looks like, in practice.

Allegro Common lisp comes with an IDE with all the bells and whistles.

Re: Why Lisp?

#68
> S-expression syntax is a well-designed serialization format

I must press, well-designed according to what measure? OP presents the well-designed serialization format as a strict positive instead of the truth: a tradeoff compared to other unnamed qualities.

Re: Why Lisp?

#69
post #52

Earlier quoted context omitted.

One difference is flow control. When you call a function, all the arguments are evaluated before being passed into the function. If you want to delay evaluation, you have to wrap the argument values in a function. When you call a macro, the text forms get passed with no evaluation. Say Clojure forgot to ship with the boolean "or". "or" should evaluate its arguments one at a time (to allow for short circuiting) and re…

I wonder how much macros are necessary one you add call-by-name parameters e.g. scala.

Or, once you have lazy evaluation (like in Haskell), for that matter.

Re: Why Lisp?

#70

Earlier quoted context omitted.

It would help if I saw a real world problem and how you can solve it Lisp and not in say Python.

How about syntactic extensions: (defmacro unless (test &body body) `(if (not ,test) ,@body))

That's a theoretical problem, not a real world problem.
Post reply on HN