Live data from Hacker News

Hyperpolyglot Lisp: Common Lisp, Racket, Clojure, Emacs Lisp

hyperpolyglot.org

31–40 of 48 posts

Re: Hyperpolyglot Lisp: Common Lisp, Racket, Clojure, Emacs Lisp

#31
post #19

Earlier quoted context omitted.

Worse: Using recursion in Common Lisp isn't idiomatic, given that CL doesn't guarantee tail-call optimisation in the specification.

Sigh. This again. All major Common Lisps support tail call optimization with proper declarations, with the exception of ABCL because it runs on the JVM. And those declarations are all identical or almost identical, so it's easy to write an implementation-specific macro to guarantee TCO if you need to do so. Some algorithms are easiest to express and read with looping constructs. For those algorithms, use looping cons…

Sigh and yet it continues to be true. You can make a pragmatic decision and rely on tail call optimisation for your specific case, but if you are writing a CL library, then it is not idiomatic to use recursion in the same way that you would for Clojure or Scheme.

Even with SBCL, for example, it doesn't have tail-call optimisation for all architectures at all optimisation levels.

Re: Hyperpolyglot Lisp: Common Lisp, Racket, Clojure, Emacs Lisp

#32
post #19

Earlier quoted context omitted.

Worse: Using recursion in Common Lisp isn't idiomatic, given that CL doesn't guarantee tail-call optimisation in the specification.

Sigh. This again. All major Common Lisps support tail call optimization with proper declarations, with the exception of ABCL because it runs on the JVM. And those declarations are all identical or almost identical, so it's easy to write an implementation-specific macro to guarantee TCO if you need to do so. Some algorithms are easiest to express and read with looping constructs. For those algorithms, use looping cons…

I think it is fair to say that the CL community is divided on whether or not relying on TCO is idiomatic.

I prefer to write my state-machines as transitioning with tail-calls, and I do get called for it. It's relatively easy to switch something written in that manner to using a loop with a trampoline, so I do so when my collaborators request it.

Re: Hyperpolyglot Lisp: Common Lisp, Racket, Clojure, Emacs Lisp

#33

Notes on CL: - why nothing on the "compiler" line? Everytime you load a snippet or a file with SBCL, it compiles it (to machine code). There's also compile-file. - interpreter: likewise, all code is compiled by default with SBCL, not interpreted, even in the REPL. To use the interpreter, we must do this: https://github.com/lisp-tips/lisp-tips/issues/52 - command line program: the racket cell shows the use of -e (eval…

> - ah ok, for dates and times

local-time has its limits (e.g. Gregorian only), but it does everything listed in this chart

> flattening a list

What? Isn't this[1] just fine ()

> hash-table literals…

Since the chart is sbcl specific, this ugly mess would technically count; a more portable (but longer) version could be made similarly using #.:

  #.(SB-IMPL::%STUFF-HASH-TABLE (MAKE-HASH-TABLE :TEST 'EQUAL) '((:X . :Y))) 
> java interop: with LispWorks or ABCL (or other libraries)

I've had good luck with .net/java interop using FOIL (written by Rich Hickey prior to Clojure).

1:

  CL-USER> (let* ((result (cons nil nil))
                 (tail result))
             (subst-if t
                       (constantly nil)
                       '(a ((b(c d)) e) f)
                       :key (lambda (x)
                              (when (and x (atom x)) (setf (cdr tail) (cons x   nil)
                                                           tail (cdr tail)))))
             (cdr result))
=> (A B C D E F)

Re: Hyperpolyglot Lisp: Common Lisp, Racket, Clojure, Emacs Lisp

#34
post #32

Earlier quoted context omitted.

Sigh. This again. All major Common Lisps support tail call optimization with proper declarations, with the exception of ABCL because it runs on the JVM. And those declarations are all identical or almost identical, so it's easy to write an implementation-specific macro to guarantee TCO if you need to do so. Some algorithms are easiest to express and read with looping constructs. For those algorithms, use looping cons…

I think it is fair to say that the CL community is divided on whether or not relying on TCO is idiomatic. I prefer to write my state-machines as transitioning with tail-calls, and I do get called for it. It's relatively easy to switch something written in that manner to using a loop with a trampoline, so I do so when my collaborators request it.

I wouldn't argue about things that are a matter of taste normally, except that I've had the experience where I've turned down optimizer settings in order to debug some code better and then the had stack overflow.

Re: Hyperpolyglot Lisp: Common Lisp, Racket, Clojure, Emacs Lisp

#36
post #6

I know that the purpose of the page is to compare syntax of common lisp, racket, clojure, and emacs lisp. But some examples could be more idiomatic, for instance instead of (defun add (a &rest b) (if (null b) a (+ a (eval (cons '+ b))))) One should avoid eval and use endp instead of null: (defun add (a &rest b) (if (endp b) a (apply #'add (+ a (first b)) (rest b))))

The use of cl:eval alone is enough to make me believe that the CL column was never reviewed by an experienced CL programmer. I am now more suspicious of the other columns, which are languages I'm far less familiar with.

Re: Hyperpolyglot Lisp: Common Lisp, Racket, Clojure, Emacs Lisp

#37
post #6

I know that the purpose of the page is to compare syntax of common lisp, racket, clojure, and emacs lisp. But some examples could be more idiomatic, for instance instead of (defun add (a &rest b) (if (null b) a (+ a (eval (cons '+ b))))) One should avoid eval and use endp instead of null: (defun add (a &rest b) (if (endp b) a (apply #'add (+ a (first b)) (rest b))))

  (defparameter *a* '(1 2 3))
  (setf (car *a*) 3)
And this is undefined behavior because it mutates literal constant. I stopped reading further. The CL column is so bad.

Re: Hyperpolyglot Lisp: Common Lisp, Racket, Clojure, Emacs Lisp

#39
post #35

CL list comprehension: (loop for file across "ABCDEFGH" nconc (loop for rank from 1 to 9 collect (format nil "~C~D" file rank)))

Or with more Python-esque syntax:

    (let ((files (coerce "ABCDEFGH" 'list))
          (ranks (loop for r from 1 to 9 collect r)))
      [(format nil "~a~a" file rank) (file 
Based on the list comprehension macro from 1991 in https://3e8.org/pub/scheme/doc/lisp-pointers/v4i2/p16-lapalm... that still works.

    (defmacro comp ((e &rest qs) l2)
      (if (null qs) `(cons ,e ,l2) ; rule A
          (let ((q1 (car qs))
                (q (cdr qs)))
            (if (not (eq (cadr q1) '
Supports filtering too, e.g.

    (let ((xs '(1 2 3 4))
          (ys '(1 2 3 4)))
      [(+ x y) (x  (3 5 5 7)

Re: Hyperpolyglot Lisp: Common Lisp, Racket, Clojure, Emacs Lisp

#40

Notes on CL: - why nothing on the "compiler" line? Everytime you load a snippet or a file with SBCL, it compiles it (to machine code). There's also compile-file. - interpreter: likewise, all code is compiled by default with SBCL, not interpreted, even in the REPL. To use the interpreter, we must do this: https://github.com/lisp-tips/lisp-tips/issues/52 - command line program: the racket cell shows the use of -e (eval…

Hash-table literals are covered by (among others):

  - Serapeum
  - golden-utils
  - rutils
  - make-hash
Though now I'm wondering which libraries would make for a proper canonical extended core... asdf, uiop (comes with asdf, so naturally), alexandria, bordeaux-threads, cffi, cl-ppcre, str, local-time, trivia,... and maybe fset? (although I personally prefer Sycamore's naming conventions)

...maybe also fivem (although I personally prefer parachute) and hunchentoot.

Post reply on HN