Текущая версия |
Ваш текст |
Строка 1: |
Строка 1: |
- | [[Практика мультипарадигмального программирования, 03 лекция (от 12 марта)|Предыдущая лекция]] | [[Практика мультипарадигмального программирования, 05 лекция (от 26 марта)|Следующая лекция]]
| + | == From Ebaums Inc to MurkLoar. == |
- | | + | We at EbaumsWorld consider you as disgrace of human race. |
- | = Встраиваемый пример ЛИСПа = | + | Your faggotry level exceeded any imaginable levels, and therefore we have to inform you that your pitiful resourse should be annihilated. |
- | | + | Dig yourself a grave - you will need it. |
- | Существует один пример встраемого Common LISP: ecl версия 0.6, документирован паршиво.
| + | |
- | | + | |
- | Есть несколько диалектов, которые ни Common, ни Схема, ни ведома зверушка. Например, есть librep, который Схема, но маскируется под ЛИСп, например, есть () и T — истина, но на самом деле это Схема. Есть тьма-тьмущая своих диалектов, икто не объясняет зачем.
| + | |
- | | + | |
- | Что показать в качестве примера встраемого ЛИСПа? Легче встраивать Схему, она часто встраивается. Но в emacs встроен eLISP, в AutoCAD встроен AutoLISP. Но AutoCAD закрытый, emacs — отдельное проишествие. В остальных случаях чаще схема. У любого приложения, ориентированного на Схему, предполагается интеграция с Си. Посему будет рассмотрена интеграция с MZ Scheme.
| + | |
- | | + | |
- | = Scheme = | + | |
- | == Отличия Scheme ==
| + | |
- | | + | |
- | * В Схеме списки, а не S-выражения.
| + | |
- | * Список верхнего уровня S-выражением не является
| + | |
- | * ...
| + | |
- | * В Схеме не различается понятия связанного с символом значения и функции
| + | |
- | Пример:
| + | |
- | Common Lisp
| + | |
- | > car
| + | |
- | Error: symbol has no value
| + | |
- | >(setq car 25)
| + | |
- | 25
| + | |
- | >car
| + | |
- | 25
| + | |
- | при этом это не мешает иметь функцию car
| + | |
- | Scheme
| + | |
- | >car
| + | |
- | #<system_function car>
| + | |
- | При этом если мы зададим значение, мы функцию потеряем.
| + | |
- | Что это позволяет:
| + | |
- | (lambda (x y) (cons x y))
| + | |
- | В Лиспе это вызовет ошибку, надо
| + | |
- | #'(lambda (x y) (cons x y))
| + | |
- | но это немного другое. В Схеме это будет вычислено.
| + | |
- | | + | |
- | Когда мы говорим (cons a b), то в Схеме все три параметра вычисляются, а в Лиспе первым элементом должна быть функция. Как следствие, в Схеме не нужен funcall.
| + | |
- | | + | |
- | === Именование ===
| + | |
- | {|
| + | |
- | !Lisp
| + | |
- | !Scheme
| + | |
- | |-
| + | |
- | |eq
| + | |
- | |eq?
| + | |
- | |-
| + | |
- | |eql
| + | |
- | |eql?
| + | |
- | |-
| + | |
- | |equal
| + | |
- | |equal?
| + | |
- | |-
| + | |
- | |
| + | |
- | |-
| + | |
- | |stringp
| + | |
- | |string?
| + | |
- | |}
| + | |
- | | + | |
- | <div class="comment">Стандарты пишутся не для того, чтобы было понгятно, я для того, чтобы у двух людей, которым было понятно, не было разногласия.
| + | |
- | | + | |
- | Но есть исключения: был человек Пастел, и его RFC читать одно удовольствие.</div>
| + | |
- | | + | |
- | == Как определяются символы в Схеме, как ввести функцию в схеме ==
| + | |
- | Есть define, он ничем не является, встречаться должен на первом уровне, он не является S-выражением.
| + | |
- | * Сопоставление символу значениея
| + | |
- | (define twenty-five 25)
| + | |
- | * Сопоставление функции
| + | |
- | ** Схемеры обычно используют такой вариант:
| + | |
- | (define (myfun arg1 arg2 ...) ...)
| + | |
- | ** Предыдущий вариант является сокращённой формой записи для
| + | |
- | (define myfun (lambda (arg1 arg2 ...) ...))
| + | |
- | | + | |
- | <div class="comment">Однажды лектор спросил у программистов на Схеме, есть ли в ней динамическое связывание, через три дня они ответили, что они нашли его. Обычно используется лексическое связывание</div>
| + | |
- | | + | |
- | == Реализация Scheme ==
| + | |
- | Существует достаточно много реализаций Схемы, соответствующих стандарту. В итоге лектор выбрал две:
| + | |
- | * guile — декларируется, что Схема там побочный эффект, а вообще это могучая система программирования, где можно будет делать вообще на всём. Но в документации там швах. А те потроха, в которых приходится копаться, ... . Причём есть два API, одно deprecated, разработчики сказали, что они его больше не будут поддерживать, но по документации оно понятно. Есть новое API, но в качестве примера его использовать нельзя. Этот интерпретатор можно и встраивать, и расширять.
| + | |
- | * mzscheme — не намного лучше, но удалось разобраться практически сразу. Написана явно на Си, с расчётом и расширения, и встраивания в Си. И те же проблемы, что и в Си, например, garbage collected. А нам нужно, чтобы S-выражения были в локальных переменных ... . Проблема в том, что чтобы запустить garbage collector, нужно знать пределы стека. Посему, там есть два способа запуска: функция, которая не возвращаем значения, и мы запускаем её навсегда. Пишем вторую функцию main, void на вход, void на выход. И если хотим возвращать значения, то делаем:
| + | |
- | main → scheme → real_main()
| + | |
- | Есть второй вариант, но он не портабельный.
| + | |
- | | + | |
- | Когда лектор добрался до примера, как его встроить, то это был экран текста, довольно запутанный.
| + | |
- | | + | |
- | Не получается так хорошо, как с Tcl, в две строчки. Дело, вероятно, в том, что Tcl широко используется, а Scheme — нет, и тем более не в качестве встроенного языка.
| + | |
- | | + | |
- | == Как расширить интерпретатор ==
| + | |
- | Обычно встраивание требуется для того, чтобы пользователь что-то написал, а чтобы он писал что-то применительно к программе, нужно, чтобы были проблемно-ориентированные функции. Оказалось, что в mzscheme это продумано достаточно хорошо.
| + | |
- | | + | |
- | * Есть тип Scheme_Object *, без звёздочки не употребляется никогда. Можно считать, что это S-выражение и есть
| + | |
- | ** Чтобы это появилось, есть два варианта:
| + | |
- | *** #include <scheme.h>
| + | |
- | *** #include <escheme.h>
| + | |
- | *** Различие в способе сборки мусора
| + | |
- | * Когда возникает написать схемовскую функцию, то она должна возвращать Scheme_Object, и получать int argc, Scheme_Object ** argv
| + | |
- | Scheme_Object * func(int argc, Scheme_Object ** argv)
| + | |
- | | + | |
- | Пример:
| + | |
- | Функция triple: делает из (a) (a a a). Или (a . (a . (a .()))).
| + | |
- | Scheme_Object * func(int argc, Scheme_Object ** argv)
| + | |
- | {
| + | |
- | /*
| + | |
- | * проверяем количество параметров,
| + | |
- | * должно быть 1, иначе ошибка
| + | |
- | */
| + | |
- | if (argc != 1)
| + | |
- | /*
| + | |
- | * правильным будет в случае не одного
| + | |
- | * параметра сообщать ошибки интерпретатору схемы
| + | |
- | */
| + | |
- | {
| + | |
- | scheme_null; //искать пустой список пришлось в исходниках
| + | |
- | }
| + | |
- |
| + | |
- | return scheme_make_pair(argv[0],
| + | |
- | scheme_make_pair(argv[0],
| + | |
- | scheme_make_pair(argv[0], scheme_null)))
| + | |
- | }
| + | |
- | | + | |
- | == Список простых функций ==
| + | |
- | === Значения ===
| + | |
- | * scheme_null ()
| + | |
- | * scheme_true #t
| + | |
- | * scheme_false #f
| + | |
- | * scheme_void — в Схеме вроде нет, нужно для того, чтобы не возвращать значения
| + | |
- | | + | |
- | === Как создавать S-выражения ===
| + | |
- | * Scheme_Object * scheme_make_pair(Scheme_Object * a, Scheme_Object * b) — создание точечной пары (обычно такие вещи называются pair)
| + | |
- | * Пусть есть строка и хочется сделать атом, который строка. Как это сделать: Scheme_Object * scheme_make_string(const char * str); Есть ещё Scheme_Object * scheme_make_string_no_copy(const char * str). В первом случае происходит копирование, во втором — просто устанавливается ссылка на существующий объект
| + | |
- | * Scheme_Object * scheme_make_integer_value(int i) — есть несколько модификаций (from_long_long, from unsigned, &hellip)
| + | |
- | * Scheme_Object * scheme_make_char(int c) — int для поддержки unicode
| + | |
- | * Scheme_Object * scheme_make_double(double d)
| + | |
- | * Scheme_Object * scheme_make_symbol(...) — пытается найти имя (char *)
| + | |
- | | + | |
- | === Как извдечь данные из Scheme_Object * ===
| + | |
- | * double scheme_real_to_double(Scheme_Object *) — единственная простая ничем не примечательная функция
| + | |
- | * int scheme_get_int_val(Scheme_Object *, long * v) — возврат значения производится через v
| + | |
- | | + | |
- | Ожидаемо, если бы были функции для извлечения строки и т. д. Но их не нашлось. Нашлось следующее:
| + | |
- | * SCHEME_STR_VAL(...) — макрос, нужно передать объект, возвращает char *
| + | |
- | * SCHEME_FLOAT_VAL(...)
| + | |
- | * SCHEME_DOUBLE_VAL(...)
| + | |
- | * SCHEME_INT_VAL(...)
| + | |
- | Предварительно надо проверить тип:
| + | |
- | * SCHEME_DOUBLEP
| + | |
- | * SCHEME_DOUBLEP
| + | |
- | * SCHEME_INTP
| + | |
- | * SCHEME_NULLP
| + | |
- | * SCHEME_STRINGP
| + | |
- | * SCHEME_PAIRP
| + | |
- | Макросы возвращают 0 в случае "нет" и 1 в случае "да"
| + | |
- | | + | |
- | === Работа со списками ===
| + | |
- | * SCHEME_CAR
| + | |
- | * SCHEME_CDR
| + | |
- | * SCHEME_CAAR
| + | |
- | * SCHEME_CDDR
| + | |
- | * SCHEME_CADR
| + | |
- | Других нет.
| + | |
- | | + | |
- | == Другой пример: nple ==
| + | |
- | nple(int quan, char c) — делает список из quan символов c
| + | |
- | Scheme_Object * nple(int argc, Scheme_Object ** argv)
| + | |
- | {
| + | |
- | Scheme_Object * res = scheme_null;
| + | |
- | int i, n;
| + | |
- |
| + | |
- | if (argc != 2)
| + | |
- | {
| + | |
- | return res;
| + | |
- | }
| + | |
- |
| + | |
- | if (!SCHEME_INTP(argv[0]))
| + | |
- | {
| + | |
- | scheme_wrong_type("nple", "integer number", 0, argc, argv); //очень похоже на то, что это longjump и return не требуется
| + | |
- | return scheme_null;
| + | |
- | }
| + | |
- |
| + | |
- | scheme_get_int_val(argv[0], &n);
| + | |
- |
| + | |
- | for (i = 0; i < n; i++)
| + | |
- | {
| + | |
- | res = scheme_make_pair(argv[1], res);
| + | |
- | }
| + | |
- |
| + | |
- | return res;
| + | |
- | }
| + | |
- | | + | |
- | == Как расширить интерпретатор ==
| + | |
- | Надо сделать сошку.
| + | |
- | | + | |
- | Сошка будет состоять из одного модуля, в ней будет три функции:
| + | |
- | * scheme_initialize
| + | |
- | * scheme_reload
| + | |
- | * scheme_module_name
| + | |
- | | + | |
- | Одна из них (scheme_initialize) даётся для инициализации интерпретатора схема и своих собственных данных.
| + | |
- | | + | |
- | scheme_reload инициализирует только интепретатор (Scheme_Env). Для начала необходима инициализация примитивов — функций, у которых есть C-обёртки. Мы сделаем обёртки и погрузим их в интерпретатор.
| + | |
- | Scheme_Object * scheme_reload(Scheme_Env * env)
| + | |
- | {
| + | |
- | Scheme_Object * proc;
| + | |
- |
| + | |
- | proc = scheme_make_prim(triple); //лучше функции объявлять как статики
| + | |
- | scheme_add_global("triple", proc, env); //не обязан быть именно примитив
| + | |
- |
| + | |
- | //со второй функцие поступим иначе — есть вариант создания примитива, при котором делается проверка аргументов
| + | |
- | proc = scheme_make_prim(nple, "nple", 2, 2); //последние два параметра — минимальное и максимальное количество параметров
| + | |
- | scheme_add_global("nple", proc, env); //не обязан быть именно примитив
| + | |
- | return scheme_void; //обычно делают так, но можно попытаться что-то создать и вернуть, проявится оно при вызове scheme_load_extension()
| + | |
- | }
| + | |
- | | + | |
- | Scheme_Object * scheme_initialize(Scheme_Env * env)
| + | |
- | {
| + | |
- | return Scheme_Reload(env);
| + | |
- | }
| + | |
- | | + | |
- | Различие: initialize вызывается только в первый раз, в остальные — reload.
| + | |
- | | + | |
- | Scheme_Object * scheme_module_name()
| + | |
- | {
| + | |
- | return scheme_false;
| + | |
- | }
| + | |
- | | + | |
- | === Как это скомпилировать ===
| + | |
- | Можно использовать gcc,
| + | |
- | | + | |
- | Можно использовать их программу, которая есть враппер для разных C-компиляторов. Сделано, вероятно, для унификации. Называется mzc.
| + | |
- | $mzc --cc sample.c ; # компиляция модуля, получим sample.o
| + | |
- | $mzc --ld sample.so sample.o
| + | |
- | | + | |
- | === Запуск ===
| + | |
- | $ mzscheme
| + | |
- | > (load-extension "sample.so")
| + | |
- | > (triple 'a)
| + | |
- | (a a a)
| + | |
- | > (nple 10 2)
| + | |
- | (2 2 2 2 2 2 2 2 2 2)
| + | |
- | | + | |
- | Тема следующей лекции: компиляция из одного языка в другой
| + | |
- | | + | |
- | {{Практика мультипарадигмального программирования}}
| + | |
- | {{Lection-stub}}
| + | |