#functional-programming #lisp #common-lisp #clisp
#функциональное программирование #lisp #common-lisp #clisp
Вопрос:
У меня есть структура в моем коде
(defstruct tree-node char freq )
И у меня есть список этих «узлов». Например (# a4, #b5, #q17), и я хочу отсортировать их в порядке убывания. Как я могу использовать функцию сортировки. Я написал функцию сравнения, но я не знаю, можно ли это сделать.
(defun compare()( if( > (tree-node-freq tree-node-freq) T (nil))))
Когда я вызываю функцию сортировки
(sort list compare)
в нем говорится, что функция сравнения не имеет значения. Кстати, я новичок в lisp, так что не судите, пожалуйста 🙂
Комментарии:
1. Вероятно, хорошая идея проверить документацию / примеры для СОРТИРОВКИ: lispworks.com/documentation/HyperSpec/Body/f_sort_.htm#sort
Ответ №1:
sort
Функция ожидает функцию-предикат, которая принимает два аргумента и возвращает обобщенное логическое значение, в то время как операционный код показывает comparison
функцию, которая не принимает аргументов. Нет причин использовать if
, когда само сравнение возвращает желаемое логическое значение. Также обратите внимание, что для доступа к функции в sort
выражении требуется кавычка, т. Е. (sort list #'compare)
Вместо (sort list compare)
.
Вы могли бы написать функцию сравнения как:
CL-USER> (defun node-greater-p (n1 n2)
(> (tree-node-freq n1) (tree-node-freq n2)))
NODE-GREATER-P
CL-USER> *nodes*
(#S(TREE-NODE :CHAR #a :FREQ 4) #S(TREE-NODE :CHAR #b :FREQ 5)
#S(TREE-NODE :CHAR #q :FREQ 17))
CL-USER> (sort *nodes* #'node-greater-p)
(#S(TREE-NODE :CHAR #q :FREQ 17) #S(TREE-NODE :CHAR #b :FREQ 5)
#S(TREE-NODE :CHAR #a :FREQ 4))
С тем же успехом вы могли бы сделать это с помощью анонимной функции:
CL-USER> *nodes*
(#S(TREE-NODE :CHAR #a :FREQ 4) #S(TREE-NODE :CHAR #b :FREQ 5)
#S(TREE-NODE :CHAR #q :FREQ 17))
CL-USER> (sort *nodes* #'(lambda (n1 n2) (> (tree-node-freq n1) (tree-node-freq n2))))
(#S(TREE-NODE :CHAR #q :FREQ 17) #S(TREE-NODE :CHAR #b :FREQ 5)
#S(TREE-NODE :CHAR #a :FREQ 4))
Но было бы еще лучше воспользоваться :key
аргументом sort
функции, которая предоставляет ключ сортировки:
CL-USER> *nodes*
(#S(TREE-NODE :CHAR #a :FREQ 4) #S(TREE-NODE :CHAR #b :FREQ 5)
#S(TREE-NODE :CHAR #q :FREQ 17))
CL-USER> (sort *nodes* #'> :key #'tree-node-freq)
(#S(TREE-NODE :CHAR #q :FREQ 17) #S(TREE-NODE :CHAR #b :FREQ 5)
#S(TREE-NODE :CHAR #a :FREQ 4))
Ответ №2:
Если вы определяете свою compare
функцию в REPL, мы видим предупреждения:
(defun compare()( if( > (tree-node-freq tree-node-freq)
T
nil)))
; in: DEFUN COMPARE
; (IF (> (SBCLI::TREE-NODE-FREQ SBCLI::TREE-NODE-FREQ) T NIL))
;
; caught ERROR:
; error while parsing arguments to special operator IF:
; too few elements in
; ((> (TREE-NODE-FREQ TREE-NODE-FREQ) T NIL))
; to satisfy lambda list
; (SB-C::TEST SB-C::THEN amp;OPTIONAL SB-C::ELSE):
; between 2 and 3 expected, but got 1
;
; compilation unit finished
; caught 1 ERROR condition
COMPARE
Вы помещаете закрывающую скобку >
слишком далеко. Вместо > a b
этого мы получили только > (a) b c
. Таким if
образом, у then нет ни предложения, ни предложения else.
Возможно, вы захотите использовать редактор с отступом lisp.
Сравнить
Просмотр sort
документации:
SORT names a compiled function:
Lambda-list: (SEQUENCE SB-IMPL::PREDICATE amp;REST SB-IMPL::ARGS amp;KEY
SB-IMPL::KEY)
Declared type: (FUNCTION
(SEQUENCE (OR FUNCTION SYMBOL) amp;REST T amp;KEY
(:KEY (OR FUNCTION SYMBOL)))
(VALUES SEQUENCE amp;OPTIONAL))
Documentation:
Destructively sort SEQUENCE. PREDICATE should return non-NIL if
ARG1 is to precede ARG2.
Inline proclamation: MAYBE-INLINE (inline expansion available)
В нем упоминаются два аргумента функции сравнения. И действительно, здесь у нас есть пример с лямбда-функцией: http://www.lispworks.com/documentation/HyperSpec/Body/f_sort_.htm
(setq tester (copy-seq "lkjashd")) => "lkjashd"
(stable-sort tester #'(lambda (x y) (and (oddp x) (evenp y))))
Ваша функция должна принимать два аргумента, tree-1
и tree-2
.
Сравните их с (> (tree-node-freq tree-1) (tree-node-freq tree-2))
.
Последние биты
(nil)
Вы вызываете функцию «nil». Просто возвращайте nil
, как вы возвращаетесь T
.
А еще лучше, используйте when
. Если значение when равно false , функция неявно возвращает nil .
(sort list compare)
Вы должны ссылаться compare
как на функцию : #'compare
. См. https://lispcookbook.github.io/cl-cookbook/functions.html#referencing-functions-by-name-single-quote—or-sharpsign-quote-