14
\$\begingroup\$

Randal Schwartz stole Lisp's decorate-sort-undecorate idiom when he came up with what we'd later call the Schwartzian transform. All of my Lisp knowledge disappeared through nine half lives, but I gave it a shot in SBCL. I'm aiming for an idiomatic example I can use in a presentation about the history of the Schwartzian transform.

This works (and I know I can generalize it further), but I wonder how Lisp-y it is:

(require :sb-posix)
(defun schwartzian-files-mtime ( glob-pattern )
    (map
        'list
        #'cdr
        (stable-sort
            (map
                'list (
                    lambda (x) (
                        cons
                            (sb-posix:stat-mtime (sb-posix:stat x))
                            x
                        )
                    )
                (directory glob-pattern)
            )
            #'<
            :key
            #'car
        )
    )
)

(schwartzian-files-mtime "/etc/*")
\$\endgroup\$
  • \$\begingroup\$ Welcome to codereview! I hope you get some nice answers ! More, feel free to visit our Perl section and answer whatever question might look interesting for you \$\endgroup\$ – яүυк Aug 11 '16 at 11:37
  • \$\begingroup\$ It's also not spelled LISP the same way that it's not spelled PERL. \$\endgroup\$ – ferada Aug 11 '16 at 13:32
  • 2
    \$\begingroup\$ @ferada LISP is LISt Processing. Perl is a name which is not an acronym. Often, LISP is capitalised as Lisp but I would posit that as wrong. \$\endgroup\$ – cat Aug 11 '16 at 14:42
  • \$\begingroup\$ Which LISP? The original LISP? This looks kinda like Scheme but more like CL. Is it CL? Which interpreter do i use to run it, and why isn't this confusing to anyone else? there are like, 10 different kinds of "real" LISP. \$\endgroup\$ – cat Aug 11 '16 at 14:44
  • 3
    \$\begingroup\$ @cat (map 'list ...) is certainly CL. Have you missed the I gave it a shot in sbcl in the quesiton? \$\endgroup\$ – Will Ness Aug 11 '16 at 16:39
16
\$\begingroup\$

What is not enough LISP-y in your function is the style used for the parentheses (they should not be left alone as last element of a line and they should be on the last line of the enclosed form). Another minor point is that you can use the shorter mapcar instead of map 'list.

Here is a version of your function (generalized for any function applied to the data and any predicate) which follows the more conventional style used in Common Lisp.

(defun schwartzian-transform (list costly-function predicate)
"sort a list of objects over the value of a function applied to them,
by applying the Schwartzian Transform (https://en.wikipedia.org/wiki/Schwartzian_transform)
the parameters are the list, the function, and the predicate for the sort." 
  (mapcar #'cdr
          (stable-sort (mapcar (lambda (x)
                                 (cons (funcall costly-function x) x))
                               list)
                       predicate
                       :key #'car)))

(require :sb-posix)
(schwartzian-transform
 (directory "/etc/*")
 (lambda (x) (sb-posix:stat-mtime (sb-posix:stat x)))
 #'<=)
\$\endgroup\$
  • 1
    \$\begingroup\$ No documentation string? \$\endgroup\$ – Gareth Rees Aug 11 '16 at 13:06
  • \$\begingroup\$ Nice transformation! The only thing I would change is to add space after lambda, although that's a small one. \$\endgroup\$ – MatthewRock Aug 11 '16 at 13:25
  • \$\begingroup\$ @MatthewRock, thanks! Sometimes I miss that space. \$\endgroup\$ – Renzo Aug 11 '16 at 13:27
  • 1
    \$\begingroup\$ @WillNess, in ANSI Common Lisp both forms are equivalent. In the Google Common Lisp Style Guide both forms are allowed. I prefer the form without the #' since it is shorter but still very clear. \$\endgroup\$ – Renzo Aug 11 '16 at 20:45
  • 1
    \$\begingroup\$ Yes I know they're equivalent, I had that impression about the style... Thanks for the link. \$\endgroup\$ – Will Ness Aug 11 '16 at 23:22
3
\$\begingroup\$

What's certainly extremely very non-LISPy is your opening parens ending the line of code like that. With that, mapcar and explicit #' in front of lambda, it could look like

(defun schwartzian-files-mtime ( glob-pattern )
    (mapcar #'cdr
        (stable-sort
            (mapcar #'(lambda (x) 
                        (cons (sb-posix:stat-mtime (sb-posix:stat x))
                              x))
                    (directory glob-pattern))
            #'<
            :key #'car)))

This looks natural to me, but still may be off w.r.t. official style guidelines. It has a "quick-n-dirty" feel to it, like something you'd scribble on the spot (not unlike Randal's original piece of code), not a proper production code with documentation string etc..

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.