Схема: претоварване на вградени процедури, общо претоварване

По-конкретно, можете ли да претоварите дисплея на процедурата на вградената схема?

По-общо, как можете да претоварите която и да е процедура в 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

Приетият отговор не претоварва функцията, а само дефинира различна функция със същото поведение.

Схемата обикновено позволява презаписване на функцията bultin, така че за да претоварите функцията (напр. 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))))))

и сега дисплеят работи по различен начин с числа. можете също да използвате потребителски типове като показване на различни типове записи по специфичен начин. Това е общ пример как да презапишете функцията bultin на всеки език, който позволява да се промени оригиналното обвързване. Записвате оригиналната функция в променлива, предефинирате функцията и ако искате как да наречете оригинална функция, използвате променливата, в която сте запазили оригинала.

Кодът може да се абстрахира в общ макрос, който ще предефинира функцията и ще изпълни вашия код на конкретни типове аргументи, така че би било правилно претоварване като в 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