Редактирование: Практика мультипарадигмального программирования, 04 лекция (от 19 марта)

Материал из eSyr's wiki.

Перейти к: навигация, поиск

Внимание: Вы не представились системе. Ваш IP-адрес будет записан в историю изменений этой страницы.

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

Текущая версия Ваш текст
Строка 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 &rarr; scheme &rarr; 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}}
+

Пожалуйста, обратите внимание, что все ваши добавления могут быть отредактированы или удалены другими участниками. Если вы не хотите, чтобы кто-либо изменял ваши тексты, не помещайте их сюда.
Вы также подтверждаете, что являетесь автором вносимых дополнений, или скопировали их из источника, допускающего свободное распространение и изменение своего содержимого (см. eSyr's_wiki:Авторское право).
НЕ РАЗМЕЩАЙТЕ БЕЗ РАЗРЕШЕНИЯ ОХРАНЯЕМЫЕ АВТОРСКИМ ПРАВОМ МАТЕРИАЛЫ!

Личные инструменты
Разделы