Схема: перегрузка встроенных процедур, общая перегрузка

В частности, можете ли вы перегрузить встроенное отображение процедур Scheme?

В более общем смысле, как вы можете перегрузить любую процедуру в Scheme?


person kud0h    schedule 09.04.2013    source источник


Ответы (2)


Схема не имеет перегрузки на основе типов а-ля Java/C++, она динамически типизирована, поэтому в ней нет смысла.

Однако вы можете сделать несколько вещей:

Вы можете перегрузить на основе структуры аргументов:

(define overload1
    (case-lambda
        ((x y) (+ x y))
        ((x y z) (+ (- x y) z))))

Это на самом деле не поможет вам, поскольку display будет принимать только один аргумент, несмотря ни на что.

(define (overload-kinda x)
    (cond
        ((list? x) (do-list x))
        ((symbol? x) (do-sym x))
        ;etc
        ))

Что хакерски, но иногда необходимо.

Мой обычный подход — это функции более высокого порядка и случай лямбда

(define my-display
    (case-lambda
        ((x) (display x))
        ((x f) (display (f x)))))

Теперь, если нам нужна специальная обработка для отображения чего-либо, мы передаем функцию для ее рендеринга.

person Daniel Gratzer    schedule 09.04.2013

Принятый ответ не перегружает функцию, а только определяет другую функцию с таким же поведением.

Схема обычно позволяет перезаписывать встроенную функцию, поэтому для перегрузки функции (например, display) вы можете использовать нечто, называемое Monkey Patch. :

(define display (let ((orig display))
                  (lambda (x . rest)
                     (let ((port (if (null? rest)
                                     (current-output-port)
                                     (car rest))))
                       (if (number? x)
                           (orig (string-append "#<" (number->string x 16) ">") port)
                           (orig x port))))))

и теперь дисплей по-другому работает с цифрами. вы также можете использовать пользовательские типы, например отображать различные типы записей определенным образом. Это общий пример того, как перезаписать встроенную функцию на любом языке, что позволяет изменить исходную привязку. Вы сохраняете исходную функцию в переменной, переопределяете функцию, и если вы хотите назвать исходную функцию, вы используете переменную, в которой вы сохранили оригинал.

Код можно абстрагировать в общий макрос, который переопределит функцию и запустит ваш код с определенными типами аргументов, поэтому будет правильная перегрузка, как в Java, а не только на основе количества аргументов, как в case-lambda.

Вот пример такого макроса (с использованием макроса типа lisp):

(define-macro (overload name-spec . body)
   (let ((name (car name-spec))
         (args (cdr name-spec)))
      `(define ,name (let ((,name ,name))
                       (lambda ,args
                          ,@body)))))

(overload (display x . rest)
   (let ((port (if (null? rest)
                   (current-output-port)
                   (car rest))))
     (if (number? x)
         (display (string-append "#<" (number->string x 16) ">") port)
         (display x port))))

(display 10)
;; ==> #<a>
(display "20")
;; ==>  20
person jcubic    schedule 04.03.2021