HiveBrain v1.2.0
Get Started
← Back to all entries
patternModerate

A Lisp version of the Schwartzian transform

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
theschwartzianlispversiontransform

Problem

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/*")

Solution

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)))
 #'<=)

Code Snippets

(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)))
 #'<=)

Context

StackExchange Code Review Q#138428, answer score: 16

Revisions (0)

No revisions yet.