Metaprogramming & higher-order functions dualis
От: __lambda__ Россия http://zen-hacker.blogspot.com/
Дата: 18.03.11 06:39
Оценка:
Я тут немного пофилософствовал на тему метапрограммирования на макросах и его дуализма с функциями высшего порядка. Давайте по порядку, начнем с самого начала. А началось все с того, что начал я изучать очень клевый язык, который называется Лисп (если быть точнее, то это семейство языков). Одним из его мощнейших свойств являются макросы. Суть в том, что с помощью них, мы можем избежать дублирования кода. А также строить полноценные мини-языки (eDSL) и т.д. Но давайте ближе к делу, то есть, ближе к коду. Рассмотрим такой участок кода на гипотетическом языке похожем на Си:
try
{
    file.assign(fname);
    file.open();
    // do something
    file.process();
}
finally
{
    file.close();
}

Такой код может часто встречаться в программе и мы вынуждены будем каждый раз дублировать его. Сразу видно, что "переменными" тут являются file, fname и код после комментария do something. Все остальное, всегда будет одним и тем же, открытие файла, обработка исключений и закрытие файла.

Что могут в данном случае нам предоставить макросы Лиспа? Давайте рассмотрим гипотетический код на языке похожем на Лисп:
(with-open-file (file fname)
    (file.process))

Этот код аналогичен вышеприведенному коду. Здесь мы видим, что тут у нас остались так называемые "переменные" участки кода. А все остальное скрывается под капотом макроса with-open-file, то есть, открытие/закрытие файла, обработка исключения все равно выполняются. Мы можем вызывать этот макрос с другими "переменными":
(with-open-file (in-file "input.txt")
    (parse-data in-file)
    (print "file parsed"))

Нам не пришлось заново писать рутину в виде обработки исключений, открытия и закрытия файла.

И достигалось бы это с помощью примерно такого гипотетического макроса:
(defmacro with-open-file (file fname rest &body)
    `(try
         (,file.assign ,fname)
         (,file.open)
         ,@body)
         (finally
             (,file.close))))

Пишу от балды, похожем на Common Lisp синтаксисе. Главное, чтобы передавало суть, основную идею.

То есть, с помощью макросов, мы можем избавиться от дублирующегося кода. Более того, вводим новую синтаксическую конструкцию with-open-file, обладающей заданной нами семантикой.

И тут я глубоко призадумался, можно ли в других языках, избавляться от такого вида дублирования кода или мы обречены писать дублирующийся код?

Ответ, да. Мы можем это сделать, но с помощью другого механизма, который называется функции высшего порядка. Это когда, функции, являются объектами первого класса, то бишь, мы функции можем хранить в переменных, передавать как параметр в другую функцию и возвращать из функции как результат. Давайте посмотрим, как можно было сделать все то же самое, что мы делали с помощью макросов, будь у нас функции высокого порядка, на гипотетическом языке похожем на Си, у которого есть функции высокого порядка:
var open-file = function (file, fname, action) {
                             try {
                                 file.assign(fname);
                                 file.open();
                                 action();
                             }
                             finally {
                                 file.close();
                             }

open-file("input1.txt", in-file1, function () { in-file1.process(); });
open-file("input2.txt", in-file2, function () { in-file2.process(); });

Таким образом мы можем избавиться от дублирующегося кода с помощью функций высокого порядка без применения макросов. Я тут у себя даже попробовал примерно нарисовать небольшой eDSL'чик. Вроде получается, например, попробовал ввести аналог цикла while:
var while = function (i, cond, body) {
                       loop {
                           if (cond(i))
                               body(i);
                           else
                               break;
                       }
                   }

var i = 0;
while(i, func (i) { i < 10 }, func (i) { print(i); });


Итого, я выдвигаю такую гипотезу, что метапрограммирование на макросах и функции высшего порядка равносильны. И что, то же самое, мы можем делать в рамках нашего языка, не меняя его синтаксис. Для опровержения моей гипотезы, достаточно привести пример такого макроса, который не возможно повторить на функциях высшего порядка. Жду ваших мыслей по этому поводу.
Computer science is no more about computers than astronomy is about telescopes (c) Edsger Dijkstra
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.