Я попытался придумать реализацию быстрой сортировки в Common Lisp, и это то, что у меня до сих пор:Как удалить избыточность в коде Lisp?
(defun quick-sort (list)
(if (cdr list)
(let ((pivot (car list)))
(append (quick-sort (remove-if-not (lambda (n) (< n pivot)) list))
(remove-if-not (lambda (n) (= n pivot)) list)
(quick-sort (remove-if-not (lambda (n) (> n pivot)) list))))
list))
Видимо это работает, но я думаю, что есть слишком много повторения в том, что код. В принципе, у нас есть три раза:
(remove-if-not (lambda (n) (< n pivot)) list)
Единственный способ три вызова отличается является >
против =
против <
.
Поэтому мой вопрос: как я мог удалить эту избыточность и сделать код более удобочитаемым и более компактным?
Конечно, я мог бы извлечь вещи функции, такие как:
(defun which (operator pivot list)
(remove-if-not (lambda (n) (funcall operator n pivot)) list))
(defun quick-sort (list)
(if (cdr list)
(let ((pivot (car list)))
(append (quick-sort (which #'< pivot list))
(which #'= pivot list)
(quick-sort (which #'> pivot list))))
list))
Но почему-то я не совсем уверен, является ли это лучший подход. Он по-прежнему чувствует себя неуклюжим, чтобы снова и снова передавать pivot
и list
.
Я также идея использовать flet
, что делает реальное тело функции более читаемым, но только перемещает сложности где-то еще:
(defun quick-sort (list)
(if (cdr list)
(let ((pivot (car list)))
(flet ((left() (remove-if-not (lambda (n) (< n pivot)) list))
(middle() (remove-if-not (lambda (n) (= n pivot)) list))
(right() (remove-if-not (lambda (n) (> n pivot)) list)))
(append (quick-sort (left))
(middle)
(quick-sort (right)))))
list))
Любые другие подходы?
Посмотрите на эту реализацию quicksort в Lisp, которую описывает Кент Питман в [Sheep Trick] (http://www.maclisp.info/pitmanual/funnies.html#sheep_trick). –