Как Я Начал Писать Макросы Для Rust На Gluon

Во многих языках есть специальный механизм генерации кода — макросы.

Иногда они реализованы на отдельном, довольно примитивном языке, основанном на простой подстановке текста (препроцессоры PL/I и C, m4), но даже в такой версии можно делать интересные и полезные вещи.

Другой популярный вариант — реализация макросов на том же языке, что и программа, в которой они используются.

Этот подход берет начало от Lisp (удобен тем, что формат программ и данных один и тот же), активно используется в Julia, OCaml (camlp4/5), Scala, Haskell, Rust и наиболее развит в Nemerle, где макрос может запускаться как до, так и после проверки типов и вывода, и в последнем варианте иметь доступ к типам.

При этом все возможности языка в макросах не нужны; например, высокая эффективность и безопасность Rust здесь не принесет никакой пользы и может только усложнить разработку.

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

Возникла идея реализовать Пролог в Nemerle, но вдруг выяснилось, что последний, несмотря на заботу одной крупной и известной компании, умер, а компилятор глючит на доступных версиях mono. Тогда я решил (надеюсь временно) снизить планку и попробовать просто функциональную, но относительно простую во встраивании глюон .

Макросы в Rust приходится упаковывать в отдельный пакет, что не очень удобно, если вы хотите разработать макрос для одноразового использования.

Так почему бы не реализовать макрос, который просто получает код Gluon в качестве параметра и выполняет его ? Теперь Gluon должен вернуть строку, которая будет анализироваться как код Rust. Мне, конечно, хотелось бы иметь возможность возвращать массив токенов, но мне не удалось получить необходимые типы в Gluon. Думаю, такой подход может быть востребован для «одноразовых» макросов.

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

Вы можете просто написать

   

static MASK: [i32; 64] = glumacro::a_proc_macro!(r#" let array = import! std.array let s = [13, 17, 42] let inl x = array.foldable.foldr (\y a -> a || x == y) False s rec let f n = if n == 64 then [] else array.append [if inl n then 1 else 0] (f (n+1)) in show (f 0) "#);

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

Теги: #Аномальное программирование #Функциональное программирование #Rust #nemerle #gluon #macro

Вместе с данным постом часто просматривают: