На каких языках вы можете переопределить методы / функции в терминах самих себя?
Я заинтересован в попытках грамотного программирования. Тем не менее, я часто, что требования изложены в общих чертах, но тогда исключения даются гораздо позже.
Например, в одном разделе будет сказано, что "Студенты не допускаются в коридоры во время занятий".
Но потом будет раздел, где говорится, что что-то вроде Учителя может дать учащемуся пропуск в зал, и в этот момент ученик может находиться в зале во время занятия.
Так что я хотел бы иметь возможность определить allowedInTheHall
после первого раздела, так что это не позволяет студентам в зале, но затем после второго раздела переопределяет allowedInTheHall
так что он сначала проверяет наличие прохода в зале, а если он отсутствует, делегирует обратно к предыдущему определению.
Таким образом, я могу представить, что эта работа - это язык, на котором:
- Вы можете переопределить метод / функцию / подпрограмму с точки зрения его предыдущего определения
- где вызывается только последняя версия функции, даже если вызывающая сторона была определена до последнего переопределения вызываемой стороны (я полагаю, это называется " поздним связыванием").
Итак, какие языки соответствуют этим критериям?
PS - моя мотивация заключается в том, что я работаю с существующими требованиями (в моем случае правила игры), и я хочу встроить свой код в существующие правила, чтобы код соответствовал структуре правил, с которыми люди уже знакомы. Я предполагаю, что такая ситуация также возникнет при попытке реализовать юридический договор.
1 ответ
Хорошо, чтобы ответить на прямой вопрос,
Вы можете переопределить метод / функцию / подпрограмму с точки зрения его предыдущего определения
... практически на любом языке, если он поддерживает две функции:
- изменяемые переменные, которые могут содержать значения функций
- некоторый оператор формирования замыкания, который фактически составляет возможность создавать новые значения функций
Таким образом, вы не можете сделать это в C, потому что, хотя он позволяет переменным хранить указатели функций, в C нет операции, которая могла бы вычислить новое значение функции; и вы не можете сделать это в Haskell, потому что Haskell не позволяет вам изменять переменную после ее определения. Но вы можете сделать это, например, в JavaScript:
var f1 = function(x) {
console.log("first version got " + x);
};
function around(f, before, after) {
return function() {
before(); f.apply(null, arguments); after();
};
}
f1 = around(f1,
function(){console.log("added before");},
function(){console.log("added after");});
f1(12);
или схема:
(define (f1 x) (display "first version got ") (display x) (newline))
(define (around f before after)
(lambda x
(before) (apply f x) (after) ))
(set! f1 (around
f1
(lambda () (display "added before") (newline))
(lambda () (display "added after") (newline))))
(f1 12)
... или целый ряд других языков, потому что это действительно довольно общие черты. Операция (которую я думаю, обычно называют "совет") в основном аналогична вездесущей x = x + 1
, за исключением того, что значение является функцией, а "сложение" - это обертывание вокруг него дополнительных операций для создания нового функционального значения.
Причина этого заключается в том, что, передавая старую функцию в качестве параметра around
или просто let
или что-то еще) новая функция закрывается над ней, на которую ссылается имя в локальной области видимости; если новая функция ссылается на глобальное имя, старое значение будет потеряно, а новая функция будет просто возвращена.
Технически можно сказать, что это форма позднего связывания - функция извлекается из переменной, а не связывается напрямую - но обычно этот термин используется для обозначения гораздо более динамичного поведения, такого как доступ к полю JS, где поле может даже не существовать. В приведенном выше случае компилятор может по крайней мере быть уверен, что переменная f1
будет существовать, даже если окажется, что null
или что-то, так что поиск быстрый.
Другие функции, которые вызывают f1
будет работать так, как вы ожидаете, если предположить, что они ссылаются на это имя. Если вы сделали var f3 = f1;
перед around
вызов, функции определены как вызывающие f3
не пострадает; Точно так же объекты, которые получили f1
передавая его как параметр или что-то в этом роде. Действует основное лексическое правило. Если вы хотите, чтобы такие функции тоже были затронуты, вы можете выполнить это, используя что-то вроде PicoLisp... но вы также делаете то, что вам, вероятно, не следует (и это больше не является какой-либо привязкой: это прямая мутация функциональный объект).
Несмотря на это, я не уверен, что это вообще дух грамотного программирования - или, в этом отношении, программа, которая описывает правила. Должны ли правила меняться в зависимости от того, как далеко вы прошли книгу или в каком порядке вы читаете главы? Литературные программы - нет, так как параграф текста обычно означает одно (вы можете не понимать его, но его значение является неизменным), независимо от того, читаете ли вы его первым или последним, так же должно быть объявление в настоящей грамотной программе, верно? Обычно никто не читает ссылку - например, книгу правил - от обложки до обложки, как роман.
Принимая во внимание, что дизайн, подобный этому, значение программы очень зависит от того, чтобы быть прочитанным с утверждениями в одном определенном порядке. Это очень удобный для машин ряд инструкций... не столько справочник.