LINUX.ORG.RU

[FFI] CL крут

 


1

3

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

http://github.com/Lovesan/virgil

//gcc -std=c99 -shared -o virgil_examples[.dll/.so] virgil_examples.c
#include <stdio.h>

typedef void (*matrix_callback)(float* matrix, int m, int n, void* param);

void print_matrix(float* matrix, int m, int n)
{
    for(int i = 0; i<m; ++i)
    {
        for(int j = 0; j<n; ++j)
            printf("%g ", matrix[i*n+j]);
        printf("\n");
    }
}

void foo (float* matrix, int m, int n, matrix_callback f, void* param)
{
    print_matrix(matrix, m, n);
    f(matrix, m, n, param);
}
(deftype matrix () '(simple-array single-float (* *)))

(define-foreign-library virgil-examples
  (t (:default "virgil_examples")))

(use-foreign-library virgil-examples)

(define-external-function "foo"
    (:cdecl virgil-examples)
  (void)
  (matrix (& (simple-array single-float) :inout))
  (m int :aux (array-dimension matrix 0))
  (n int :aux (array-dimension matrix 1))
  (callback pointer)
  (param (& float :in t) :optional void))

(define-callback add-number
    void ((data pointer) (m int) (n int) (param (& float :in t)))
  (with-value (matrix data `(simple-array single-float (,m ,n)) :inout)
    (let ((param (if (voidp param) 0.0 param)))
      (dotimes (i m)
        (dotimes (j n)
          (incf (aref matrix i j) param))))))

(defun main (matrix)
  (declare (type matrix matrix))
  (format t "~&Matrix:~%~a~%" matrix)
  (force-output *standard-output*)
  (foo matrix (get-callback 'add-number) 1.0)
  (format t "~&After processing:~%~a" matrix))
* (defparameter *matrix* (make-array '(4 4) :element-type 'single-float
                           :initial-contents '((1.0  2.0  3.0  4.0)
                                               (5.0  6.0  7.0  8.0)
                                               (9.0  10.0 11.0 12.0)
                                               (13.0 14.0 15.0 16.0))))
;;==> *MATRIX*

* (main *matrix*)
;;на stdout ==>
Matrix:
#2A((1.0 2.0 3.0 4.0)
    (5.0 6.0 7.0 8.0)
    (9.0 10.0 11.0 12.0)
    (13.0 14.0 15.0 16.0))
1 2 3 4
5 6 7 8
9 10 11 12
13 14 15 16
After processing:
#2A((2.0 3.0 4.0 5.0)
    (6.0 7.0 8.0 9.0)
    (10.0 11.0 12.0 13.0)
    (14.0 15.0 16.0 17.0))
Даже питоновский ctypes и рядом не валялся, особенно в плане производительности.

Ответ на: комментарий от Love5an

> В CL это никому не надо.
И посему CL представляет из себя секту. Есть правила стиля речи или, если угодно, правила сжатия информации при передаче. Лисперы, по моему мнению, должны обладать достаточным интеллектом и склонностью к обобщению, чтобы попытаться применить эти принципы (весьма общие) к своему языку программирования. Ведь недаром, недаром неопределённый артикль в английском языке записывается как «a», а не как «multiple-value-bind».

Если известно, что речь идёт о таком-то рекорде, то нет смысла в многократном повторении его имени. with-accessors в случае рекордов работает тухло (проверялось в своё время), во всяком случае, это так в некоторых реализациях CL. А классы вообще зачастую работают тухло. Так что выбирать остаётся не из чего. Что касается with-accessors, то необходимость перечислять слоты сводит всё удобство на нет, если к полю нужно обратиться один или два раза. В «покалеченных» языках достаточно один раз написать имя типа при объявлении переменной и всё.

На практике же, лисперы этого не понимают несмотря на всю очевидность. И в этом состоит покалеченность головы лисперов :P

FFI(то, что у меня) и Groveller - вещи довольно перпендикулярные.

Я не силён в FFI. Один раз, по сути, пользовался Groveller-ом, когда баловался с fuse. Основная трудность, как выяснилось - это #define в исходниках ядра, их и Groveller не особо-то берёт. Тяжело это было, в итоге без ручного труда всё же не обошлось и не получилось написать переносимо, пришлось кое-где выкапывать значения #define и куда-то там их ручками прописывать. А тему с начала, да, не читал, зачем, таких тем много, и в них главное - это самому пофлудить :-) Я тут в виде пятой колонны как бы выступаю. А вообще, пора спать!

den73 ★★★★★
()
Ответ на: комментарий от den73

>Лисперы, по моему мнению, должны обладать достаточным интеллектом и склонностью к обобщению, чтобы попытаться применить эти принципы (весьма общие) к своему языку программирования. Ведь недаром, недаром неопределённый артикль в английском языке записывается как «a», а не как «multiple-value-bind».

Какие принципы? При чем тут артикли? У тебя шизофрения или ты просто любишь скушать интересных таблеток на ночь?

>И посему CL представляет из себя секту.

И в эту секту тебя, надо понимать, не приняли? И именно поэтому ты теперь при каждом удобном, и не очень, случае жалуешься на то, какие лисперы плохие, айайай, не хотят поменять стандарт и зделать как в крузисе добавить возможность доступа к структурам через точку, как в моднявых мейнстримных языках с сиподобным(или паскалеподобным) синтаксисом?

>with-accessors в случае рекордов работает тухло (проверялось в своё время), во всяком случае, это так в некоторых реализациях CL.

WITH-ACCESSORS это тривиальнейший макрос. Чему там работать «тухло», я понять в принципе не могу. Ну, нехер пользоваться заброшенными реализациями, которые даже стандарт CL на тему символьных макросов осилить не могут.

>А классы вообще зачастую работают тухло. Нехер пользоваться древними, не работающими, и не поддерживаемыми реализациями.

>Если известно, что речь идёт о таком-то рекорде, то нет смысла в многократном повторении его имени.

Я тебе сейчас тааакой секрет открою, только никому не говори. Даже два. Первый такой - опция :CONC-NAME в DEFSTRUCT.

Второй такой:

В CL динамическая типизация. Реализация доступа через «точку» в языках с динамической типизацией требует как минимум динамической(ран-тайм) проверки типа структуры.

Объекты, классы которых определяются с помощью DEFSTRUCT в основном используются в местах, критичных к производительности(в местах, где использовать жирные и тормозные CLOS-объекты очень нежелательно), т.е. в таких местах, где динамический lookup типа структуры и положения слота при каждом обращении к оному добавил бы много нежелательного оверхеда. Это, фактически, чуть ли не единственная причина, по которой defstruct-объекты находятся в стандарте CL(вторая - совместимость со старыми лиспами)(вообще говоря, в стандарте присутствует довольно много вещей, учитывающих тонкие(да и толстые) моменты производительности приложений на лиспе в «реальном мире», и в т.ч. за это мне CL и нравится, в отличие от Схемы той же). Поэтому для доступа к их слотам DEFSTRUCT при компиляции генерирует функции(да и не обязательно даже функции), в которых алгоритм доступа к определенному слоту определенной структуры захардкожен. А это позволяет крайне эффективный доступ к слотам, особенно если функции инлайнятся, буквально настолько же эффективный, как и доступ к полям структуры в Сях.

«Динамический» же доступ в CL используется для слотов объектов CLOS-классов. Только оператор аналогичный, скажем, питоновскому оператору ".", в CL называется «SLOT-VALUE», и записывается, как и все в лиспе, в префиксной форме. Но я тебе лично разрешаю его переименовать в «DOT», или даже в "->".

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

Love5an
() автор топика
Ответ на: комментарий от den73

> Есть правила стиля речи или, если угодно, правила сжатия информации при передаче. Лисперы, по моему мнению, должны обладать достаточным интеллектом и склонностью к обобщению, чтобы попытаться применить эти принципы (весьма общие) к своему языку программирования. Ведь недаром, недаром неопределённый артикль в английском языке записывается как «a», а не как «multiple-value-bind».

в этом плане весьма разумными выглядят мысли David Moon о PLOT:
http://users.rcn.com/david-moon/PLOT/ . Там по ангельски: def fib(x is integer), defproto forall (c as collection), и т.п.
Я только не понял, этот PLOT — концепт или где-то скачать можно рабочий конпелятор?

anonymous
()
Ответ на: комментарий от anonymous

> PLOT — концепт или где-то скачать можно рабочий конпелятор?

концепт

paranonymous
()
Ответ на: комментарий от Love5an

> В CL динамическая типизация. Реализация доступа через «точку» в языках с динамической типизацией требует как минимум динамической(ран-тайм) проверки типа структуры.

не всегда и не везде требует. Во-первых, google://«predicate dispatch» http://www.cs.ucla.edu/~todd/research/oopsla04.pdf http://www.cs.ucla.edu/~todd/research/oopsla04.html http://www.cs.washington.edu/homes/mernst/pubs/dispatching-ecoop98-abstract.html ftp://publications.ai.mit.edu/ai-publications/2001/AITR-2001-006.pdf http://lambda-the-ultimate.org/node/356

 — вывод, такие проверки (динамические, в ран-тайме) в большей части можно вынести «за скобки» какого-то предиката, вычисляемого/обновляемого в компайл-тайме или в некоторых местах в рантайме (а не всех, как было ранее).

Во-вторых, gradual typing — как перейти от динамической типизации к статической через опциональные аннотации типов и вывод типов по этим аннотациям. См. ссылки выше.

В-третьих, проверки на тип структуры в некоторых случаях могут быть сильно ускорены (булевы предикаты, bloom-фильтры на булевы матрицы, и т.п.). Сюда же tagged pointer и т.п.

в таких местах, где динамический lookup типа структуры и положения слота при каждом обращении к оному добавил бы много нежелательного оверхеда. Это, фактически, чуть ли не единственная причина, по которой defstruct-объекты находятся в стандарте CL


а) именно при каждом обращении — не нужно
б) костыль, однако. defstruct-объекты как pod vs. CLOS-объекты — это «предварительная оптимизация»
в) а был ли оверхед, в реальном приложении — это ещё ХЗ, смотреть надо профилятором

anonymous
()
Ответ на: комментарий от anonymous

> вывод, такие проверки (динамические, в ран-тайме) в большей части можно вынести «за скобки» какого-то предиката, вычисляемого/обновляемого в компайл-тайме или в некоторых местах в рантайме (а не всех, как было ранее).

можно и они выводятся за скобки компилятором. Если компилятор не может вывести - все долго и в рантайме.

paranonymous
()
Ответ на: комментарий от anonymous

> не всегда и не везде требует. Во-первых, google://«predicate dispatch»

Как это вообще связано-то, а? Предикатный диспатчинг, который кстати делается в клос фактически в 10 строк, и проверка типа при диспатчинге по классам?

paranonymous
()
Ответ на: комментарий от paranonymous

А ты подумай. Проверка типа — это вычисление предиката на соответствие типу. Мультидиспетчеризация, диспетчеризация по типу первого (vtable), :around, :before, :after, контракты (с натяжной, тут нет диспетчеризации, или диспетчеризация в «ошибку компиляции») и исключения/условия (по аналогии с контрактами, только в рантайме) — это всё частные случаи predicate dispatch, с разными предикатами (которые большей частью можно посчитать во время компиляции)

anonymous
()
Ответ на: комментарий от anonymous

> это всё частные случаи predicate dispatch, с разными предикатами (которые большей частью можно посчитать во время компиляции)

Нельзя.

paranonymous
()
Ответ на: комментарий от anonymous

> это всё частные случаи predicate dispatch, с разными предикатами

(которые большей частью можно посчитать во время компиляции)


На самом деле есть большое несоответствие между максимально возможными оптимизациями на этапе компиляции и интерактивной разработкой, во время которой постоянно меняется код и предположения, верность которых не вызывала сомнений, вдруг обесцениваются.

Время компиляции в подавляющем числе случаев совпадает со временем разработки, т.е. её нельзя трактовать как просто стадию обработки кода. Код правят и тут же компилирует, небольшими кусочками. И система должна продолжать вести себя правильно.

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

archimag ★★★
()
Ответ на: комментарий от paranonymous

можно. Если у тебя есть вся полная требуемая информация о типах из аннотаций. Из этих аннотаций можно вывести теорему и доказать её в compile time.
Этим примерно и отличается gradual typing от того что в sbcl — что по семантике что-то можно вывести и доказать, то что требуется твоим предикатам, а не то, что встроено в sbcl.

anonymous
()
Ответ на: комментарий от anonymous

> Из этих аннотаций можно вывести теорему и доказать её в compile time.

После этого разработчик перекомпилировал какой-либо из кусков кода, доказательство оказалось неверным и система упала с непонятным сообщением об ошибке.

archimag ★★★
()
Ответ на: комментарий от anonymous

> можно. Если у тебя есть вся полная требуемая информация о типах из аннотаций. Из этих аннотаций можно вывести теорему и доказать её в compile time.

бугага, еще один начинающий штангист неосилятор. Неужто можно решить задачу вывода типов для систем сложнее System F?

Этим примерно и отличается gradual typing от того что в sbcl — что по семантике что-то можно вывести и доказать, то что требуется твоим предикатам, а не то, что встроено в sbcl.

Дооо, иди дочитай душкина, а потом приходи на лор. Для динамической типизации нет задачи «вывода типов» - она уже решена, если у нас есть тип общий тип t. Ладно, заканчиваю с тобой спор, ибо это бесполезно.

paranonymous
()
Ответ на: комментарий от paranonymous

> сложнее System F

Зачем тут «сложнее System F»? Под системой типов я понимаю $\lambda_{\rightarrow}^{?\alpha}$ , то есть, polymorphic gradually typed lambda calculus , под «выводом типов» — unification-based inference.
Под «можно вывести теорему в compile-time» — подразумевается, что ill-typed terms не принимаются, и случаи «теорема обломалась», «теорема не вычислима в compile time» решаются диспетчеризацией в «большую красную кнопку» на этапе разработки, вроде юнит-тестов.
Под «частными случаями, которые можно посчитать в compile time» — понимается не все абстрактные типы лямбда-куба в раёне правого верхнего его угла, а практически полезные приёмы для оптимизации тех мест, где «динамическая диспетчеризация тормозит» (если она вообще тормозит), вроде выбора, какая ООП система будет эффективнее в данной ситуации, vtable (генерируемая автоматически, по предикатам, а не жёстко заданной иерархией) или clos (и динамика).

для динамической диспетчеризации нет задачи вывода типов она уже решена у нас есть общий тип t


она решена, скажем так, неэффективно. И решена как компромис между вычислением чего-то частично в рантайме, частично во время компиляции. Дык вот, смысл не в том чтобы всё полностью переложить на время компиляции (что потребует вывод всех типов), а в том, чтобы практически оптимизировать только выгодные места. Не выводя типы там где не надо.

anonymous
()
Ответ на: комментарий от anonymous

> она решена, скажем так, неэффективно

На основании чего сделан такой вывод? Какие проблемы с производительностью программ на CL вы имеете? Подтверждаются ли ваши вывода профайлером?

а в том, чтобы практически оптимизировать только выгодные места.

Не выводя типы там где не надо.



Хм, а разве сейчас делается не так?

archimag ★★★
()
Ответ на: комментарий от archimag

Расскажите лучше, как вы рефакторите библиотеки. У меня (да и у всех, думаю), поначалу новая функция пихается куда попало, а потом наступает время сортировки по пакетам. Как это делать?

anonymous
()
Ответ на: комментарий от anonymous

> Зачем тут «сложнее System F»?

Не знаю, в хаскелле зачем-то понадобилась :) Да и вообще system F, всясечкие типизированные лямбда исчисления и полновесный вывод типов вообще никак не ложится на системы с eval и хитрым ООП, т.е. к реально существующим динамическим и не только языками, не имеющим под собой сухого математического формализма, слабо относятся. А значит, нужны только штангистам.

Под «можно вывести теорему в compile-time» — подразумевается, что ill-typed terms не принимаются, и случаи «теорема обломалась», «теорема не вычислима в compile time» решаются диспетчеризацией в «большую красную кнопку» на этапе разработки, вроде юнит-тестов.

Да ладно, ты думаешь в обычном компиляторе это не оптимизируется и не используется? Ты думаешь sbcl не способен вызов метода оптимизировать сразу на нужный метод, если при компиляции известен класс? И что не предупредит о возможных ошибках типизации? Ты глубоко ошибаешься.

она решена, скажем так, неэффективно. И решена как компромис между вычислением чего-то частично в рантайме, частично во время компиляции. Дык вот, смысл не в том чтобы всё полностью переложить на время компиляции (что потребует вывод всех типов), а в том, чтобы практически оптимизировать только выгодные места. Не выводя типы там где не надо.

Что за бред? Почему не вывести типы везде, где это можно?

paranonymous
()
Ответ на: комментарий от anonymous

> У меня (да и у всех, думаю), поначалу новая функция пихается куда

попало, а потом наступает время сортировки по пакетам.

Как это делать?



Пакет это одна из единиц декомпозиции. Разбивка по пакетам должна иметь вполне определённый, чёткий и конкретный смысл. А когда этот смысл обнаружен, то думаю и вопрос отпадает сам собой. За не именем этого смысла лучше работать в одном пакете. Или в чём заключается вопрос?

Расскажите лучше, как вы рефакторите библиотеки.

потом наступает время сортировки по пакетам.



Я, вообще говоря, не уверен в уместности слова «потом». Критическое переосмысление кода и соответствующее изменение у меня происходят постоянно, пусть даже и по немного. Т.е. я бы вообще не разделял стадии разработки и рефакторинга.

archimag ★★★
()
Ответ на: комментарий от anonymous

> Расскажите лучше, как вы рефакторите библиотеки. У меня (да и у всех, думаю), поначалу новая функция пихается куда попало, а потом наступает время сортировки по пакетам. Как это делать?

www.flownet.com/gat/packages.pdf - вам в помощь.

paranonymous
()
Ответ на: комментарий от paranonymous

den73, пароль забыл дома

я же не спрашиваю, как работают пакеты. Я спрашиваю, как вы с этим боретесь. Конкретнее - как произвести рефакторинг без многократной пересборки образа.

anonymous
()
Ответ на: den73, пароль забыл дома от anonymous

> Конкретнее - как произвести рефакторинг без многократной

пересборки образа.


А зачем его пересобирать вообще? С чем вообще связана необходимость пересборки? Я процесс перезапускаю обычно раз в несколько дней.

archimag ★★★
()
Ответ на: den73, пароль забыл дома от anonymous

> Конкретнее - как произвести рефакторинг без многократной пересборки образа.

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

paranonymous
()
Ответ на: комментарий от archimag

И Вам тот же вопрос - сколько Ваших пакетов в вашем самом большом проекте.

anonymous
()
Ответ на: den73 от anonymous

> Хорошо. Вот у Вас есть самая большая программа.

У меня не бывает больших программ, ибо я бью их на небольшие библиотеки.

Сколько в ней ваших пакетов?


Ну, пусть будет 5 (не считал).

archimag ★★★
()
Ответ на: den73 от anonymous

никогда не считал. Моих - порядка 5-6. Вообще же советуют делать пакеты большими.

paranonymous
()
Ответ на: комментарий от archimag

den73

Ну, в лиспе я не вижу особой разницы между библиотекой и программой. Сколько пакетов, включая Ваши библиотеки и собственно прикладной код? И заодно, сколько файлов с исходниками (само приложение и библиотеки) и объём кода в КБ?

anonymous
()
Ответ на: den73 от anonymous

Вот ты предлагаешь подсчитать. Всего у меня сейчас около 20 000 строк на CL написано. Ну пара-тройка десятков пакетов найдётся.

archimag ★★★
()
Ответ на: den73 от anonymous

> Ну, в лиспе я не вижу особой разницы между библиотекой и программой.

В лиспе вообще программ нет. Но разница между системами (ASDF) и пакетам есть.

archimag ★★★
()
Ответ на: комментарий от archimag

Вот допустим есть функция в пакете X, и Вы решили её перенести в пакет Y. Или выяснилось, что пакет X надо разбить на два пакета Y и Z. Ваши действия, по пунктам.

anonymous
()
Ответ на: комментарий от anonymous

Естественно, при этом существуют зависимости, эта функция вызывается ещё в каких-то пакетах A и B.

anonymous
()
Ответ на: комментарий от anonymous

Т.е., я имел в виду, в пакетах A и B есть функции a:g и b:h, к-рые вызывают исходную функцию, которая сейчас есть x:f, а должна стать y:f.

anonymous
()
Ответ на: комментарий от anonymous

Это бывает очень редко, потому что packages not namespaces. Изначально, пакеты создавались, чтобы не было name-clashes между символами при использовании нескольких систем, т.е. фактически, packages должны быть отделены друг от друга как можно сильнее. Они не служили изначально для логического разделения модулей как это, например, в java или в python. В стандартной библиотеке нет отдельного cl-user.math или cl-user.string и прочее. В идеале система - это один большой пакет, а не множество маленьких, но логически разнясчщихся пакетов. Они для другого и по-другому работают. Использование их для не подходящих для этого целей приводит к проблемам. Если вдруг возникла необходимость бить пакет на 2 отдельных - это значит, надо бить библиотеку на две маленьких.

paranonymous
()
Ответ на: комментарий от anonymous

den73

А вот пара кусков моего кода на лиспе, чтобы больше ни у кого не возникало желание объяснять мне существование опции conc-name или отличия пакетов от asdf-систем :-P

(def-firebird-macro-1 M_конец_месяца (date-expr) 
  (fbody dateadd(day,-1,dateadd(month,1,M_начало_месяца(:~date-expr)))^))

(def-stored-procedure fo_poluchit_datu_rascheta
  :doc "1С.Форма-Документ.ФинОтчет.ПолучитьДатуРасчета"
  :args '((СрокОпл int)
          (ДатаПер simple_date))
  :vars '((ДатаКон simple_date))
  :returns '((ДатаНач simple_date))
  :body (fbody
 ДатаКон= M_конец_месяца(ДатаПер);
 ДатаНач=dateadd(-СрокОпл day to ДатаКон);
 ДатаНач=~~($min ($начало-месяца (fbody ДатаПер^)) (fbody ДатаНач^));
 suspend;
^))

anonymous
()
Ответ на: den73 от anonymous

> А вот пара кусков моего кода на лиспе

А тут точно есть профит от использования CL? Ибо писать stored procedures для firebird c 1С честно намного легче на SQL, чем на таком лиспе, как мне кажется.

paranonymous
()
Ответ на: комментарий от paranonymous

den73

> packages not namespaces

Если так, то в Cl нет namespaces. Я правильно понял Вашу мысль?

Если вдруг возникла необходимость бить пакет на 2 отдельных - это значит, надо бить библиотеку на две маленьких.

Хорошо, переформулируем задачу. Имеется библиотека, которая разрослась и которую пора бы разбить на две маленьких. Очевидно, две разные библиотеки должны находиться в двух разных пакетах. Задача остаётся прежней, меняется только мотивация.

Кстати, я посчитал, в моём образе сейчас 19 моих пакетов, включая библиотеки. Всего в образе 140 пакетов. По сравнению с этим, в дельфийской программе порядка 60 моих модулей (каждый модуль - это пространство имён и каждый класс - это тоже пространство имён), а всего в ней, думаю, с полтысячи модулей. Также у меня есть база данных firebird, в ней нет пространств имён, поэтому имена объектов в ней - длинные и уродливые. Объектов порядка двух тысяч.

Объём лисп-кода в данном проекте - 1мб, 22000 строк, правда, это не всё чистый лисп, есть и метаданные для СУБД. 82 файла.

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

anonymous
()
Ответ на: комментарий от paranonymous

den73

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

Я считаю, что профит есть, поскольку: 1. У меня есть среда, в которой я могу заводить свои переменные. В ibexpert тоже вроде есть что-то подобное, но после первого access violation я больше не пытался это запускать. 2. В лиспе я веду скрипты обновления БД, которые написаны на лиспе, а не на чём-то другом и это удобно по той же причине наличия среды с переменными. 3. Я не пишу на 1С, я перевожу с 1С на файрбёрд+delphi (нужно ли это - лучше спросить не у меня, а у моих работодателей, мне за это, во всяком случае, платят деньги). 4. Было время, когда было очень сложно поменять код на файрбёрде - этому мешали зависимости между объектами БД. Чтобы поменять сигнатуру фунции или структуру БД, нужно развязать всю цепочку зависимостей, а потом завязать её обратно. Сейчас этому отчасти помогает ibexpert, но я сделал более автоматизированное решение задачи. 5. Я использую в firebird макросы. Например,

BUDDEN 98 > fbody M_конец_месяца(current_date)^
"  dateadd(day,-1,dateadd(month,1, dateadd(day,1-extract(day from current_date),current_date)))"
И это ещё - достаточно простой макрос. Хотя, возможно, конкретно данная функция есть в какой-нибудь udl библиотеке, но ведь там есть не всё. Или вот пресловутый полиморфный максимум:
BUDDEN 99 > fse M_MAX('a','b') from dual; 
(("b"))
#("CASE")
Есть ли профит от макросов? 6. Поскольку fbody вызывает лексер, понимающий синтаксис firebird, это позволяет мне использовать Русские слова в качестве идентификаторов без занудных кавычек. Поскольку я перевожу с 1С, это сводит некоторые операции к копипасту.
BUDDEN 101 > format t "~A" (fbody Русский<>Englsh^)
 "Русский"<>Englsh

anonymous
()
Ответ на: den73 от anonymous

> Если так, то в Cl нет namespaces. Я правильно понял Вашу мысль?

нет, неправильно.

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

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

Кстати, я посчитал, в моём образе сейчас 19 моих пакетов, включая библиотеки

И сколько в одной библиотеке пакетов?

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

alt + . юзать вместо alt + tab?

paranonymous
()
Ответ на: den73 от anonymous

> Если так, то в Cl нет namespaces.

Совершенно верно! Я тоже уже устал всем повторять эту мысль, что packages не являются прямым аналогом namespace, у них другой смысл. И само понятие namespace для CL не вполне уместно, ибо символы.

Имеется библиотека, которая разрослась и которую пора бы разбить

на две маленьких.



Ты спрашиваешь про slime-who-calls? Или интересуют более примитивные техники?

archimag ★★★
()
Ответ на: комментарий от paranonymous

den73

>> Если так, то в Cl нет namespaces. Я правильно понял Вашу мысль?

нет, неправильно.

Хорошо, если это не пакеты, то что же тогда такое namespaces в лисп?

И сколько в одной библиотеке пакетов?

По 1-2-3. Но я не считаю это правильным, а признаю, что это вынужденная ситуация, связанная именно с неудобством работы с пакетами в CL. Модульная организация программ придумана не зря. Конечно, можно принять за аксиому, что CL идеален и все идеи, которые в нём реализованы плохо, просто не нужны (как следствие аксиомы). На самом же деле, модульность - это вещь естественная и нужная. Вполне естественно не трогать код, который устоялся, и пусть он лежит в отдельных файлах до момента великого merge. Есть полу-throwaway код, который нельзя выкинуть совсем, но следует вынести в «заштатный» модуль, чтобы он не мешался. А новый функционал хорошо реализовывать в новых, отдельных модулях до момента великого merge. Просто, чтобы ничего не сломать в том, что уже работает. Также естественно разбивать код на модули согласно логической структуре. В лиспе всё это у меня получается туго, по сравнению с Паскалем. Несмотря на то, что в Паскале я пользуюсь только родными средствами, а в лиспе у меня было примерно четыре подхода к созданию средств, которые бы мне упрощали эту задачу. Вот они:

- перешибленная везде readtable, позволяющая (переносимо) вешать хуки на intern и find-symbol - слежение за именами символов, чтобы предотвратить создание мусорного символа с конкретным именем (пользуюсь почти всегда, когда нужно переместить символ в другой пакет) - альтернативная функция find-symbol, позволяющая видеть символы из нескольких пакетов без создания нового пакета (работало, но проблемы не решило) - функция, выискивающая потенциальные мусорные символы и показывающая их - различные макросы поверх defpackage, чтобы автоматизировать алгебру пакетов, а не экспортировать символы по одному - также я пробовал Tim Bradshaw's hierarchicl packages.

Итог - я всё равно недоволен системой пакетов лиспа и всё равно получается единственный прагматичный выход - это разместить код в небольшом количестве пакетов и как можно реже что-то в этом менять. Но это противоречит congruent-lambda-list. Если нам нужен метод add с двумя параметрами, то когда-нибудь понадобится метод add с тремя параметрами и тут мы опять будем вынуждены вернуться к проблеме пакетов.

Может быть, мне не хватает упорства, и именно потому я хочу знать, кто и как решает этот вопрос.

Мне вместо этого объясняют, что это ненужно и идеологически неправильно. Но я-то знаю, что мне это нужно. Либо Вы знаете, как это сделать, либо нет - тогда так и скажите.

alt + . юзать вместо alt + tab?

Альт + . это у меня «найти определение», не понял, к чему это?

anonymous
()
Ответ на: комментарий от archimag

den73

> Ты спрашиваешь про slime-who-calls

И как ты это себе представляешь? Библиотека X состоит, допустим, из 10 функций. Они используются в каком-то коде. Хорошо, если он загружен в образ (а он может быть и не загружен). Что, берём, вручную вызываем slime-who-calls, заходим в каждую функцию, смотрим, в каком она пакете, прописываем соответствующий import. Т.е., это ручная работа, нанизывание бус из бисера на леску.

Далее пересобираем образ, т.к. если мы ошиблись, то это всплывёт через неделю, когда уже забудется.

И при наличии макросов всё это вряд ли будет работать.

Но почему же в Паскале всё это делается на порядок проще?


namespace для CL не вполне уместно, ибо символы

Думаю, наиболее общее определение namespace - это «средство для разрешения имён в сущности», и в этом смысле package=namespace. Просто с немного другими свойствами.

В любом случае, как достичь модульности, если не использовать пакеты? Вспомним C и будем писать префикс к каждой функции? Ну это же просто смешно! Я же сижу за компьютером не оттого, что люблю печатать или рассматривать буковки. Я сижу, чтобы быстрее сделать свою работу.

anonymous
()
Ответ на: den73 от anonymous

> На самом же деле, модульность - это вещь естественная и нужная. Вполне естественно не трогать код, который устоялся, и пусть он лежит в отдельных файлах до момента великого merge. Есть полу-throwaway код, который нельзя выкинуть совсем, но следует вынести в «заштатный» модуль, чтобы он не мешался. А новый функционал хорошо реализовывать в новых, отдельных модулях до момента великого merge. Просто, чтобы ничего не сломать в том, что уже работает.

Вы что, работаете сразу на боевых серверах? И какой великий мердж? Почему же не небольшие инкрементальные изменения, оставлюящие код в рабочем состоянии? Почему не использовать git, darcs, mercurial, чтобы разбивать бранчи и параллельно работать над несколькими фичами? Честно говоря, для меня дикость такой стиль программирования. Мне кажется, что проблемы решаются не теми средствами, какими их бы следовало решать, вот и все.

Мне вместо этого объясняют, что это ненужно и идеологически неправильно. Но я-то знаю, что мне это нужно. Либо Вы знаете, как это сделать, либо нет - тогда так и скажите.

Объясняют, как легче, а не как идеологически правильнее. Легче пользоваться большими пакеджами, потому что, по-другому в лиспе не получится, с этим надо смириться. Лисп не паскаль, не ява, не питон, руби и пхп, у этих - свои ограничения.

paranonymous
()
Ответ на: den73 от anonymous

> Хорошо, если он загружен в образ (а он может быть и не загружен).

Почему не заргужен? Загрузи.

Далее пересобираем образ


Зачем пересобираем? slime-undefine-function, grep, отладчик тут же после исправления всё покажет, если где накосячили. Вызовов ведь не бывает слишком много.

И при наличии макросов всё это вряд ли будет работать.


Поэтому с использованием макросов и надо быть очень и очень острожным.

namespace - это «средство для разрешения имён в сущности»


Ок, но пакет это коллекция символов с парой плюшек.

Вспомним C и будем писать префикс к каждой функции?


Это очень хорошая практика, когда по одному названию функцию можно судить о том, что она делает, очень упрощает чтение и понимание кода. Тут недавно Линус высказывался на эту тему, что мол одна из причин, почему С лучше, чем С++. Серьёзно, я читаю регулярно довольно много кода на PHP, Pytho, C, C++ и CL и сложнее всего мне понимать Python (хотя я на нём и писал довольно много) иммено из за этого, ибо хрен поймёшь что тут на самом деле вызывается, надо весь код смотреть.

Я же сижу за компьютером не оттого, что люблю печатать


Просто научись печатать, я набираю примерно 400 символов в минуту и вообще не понимаю в чём заключается проблема.

archimag ★★★
()
Ответ на: комментарий от paranonymous

У меня вот в ходе именно этой беседы возникла следующая идея, как сделать подобно Паскалю (надо сказать, уже далеко не первая попытка)

Нужно сделать пакет Z, комфортабельно импортирующий всё, что можно, из пакетов A,B,C. Делаем макрос

(def-comfortable-package Z (:use* &rest ABC) &rest other-defpackage-options) ...)
который: берёт пакеты A,B,C, вычисляет все clashes между ними. Каждое имя из clashes он интёрнит в спец. пакет :clashed-symbols. И генерирует форму
`(defpackage Z (:use ,@ABC) 
  (:shadowing-import-from :clashed-symbols ,@clashed-symbols) ,@other-defpackage-options
Перешибаем (read) так, чтобы при попытке считать символ из пакета :clashed-symbols выдавалась ошибка (наиболее осторожная политика, хотя можно, например, брать самый первый подходящий символ по порядку пакетов ABC). Read у меня уже давно перешиблен и сделать такую проверку для меня как два байта.

Сейчас я пользуюсь точно таким же методом, только вместо use он использует :import-from с явным перечислением импортируемых символов, а это значит, что при добавлении новых символов они не попадут в зависимые пакеты до того, как их определения будут перекомпилированы. С другой стороны, мой теперешний метод работает и без перешибания (read). Видимо, нужно просто добавить второй метод в мой нынешний макрос.

всего мне понимать Python (хотя я на нём и писал довольно много) иммено из за этого, ибо хрен поймёшь что тут на самом деле вызывается, надо весь код смотреть.

Интересно, а это разве не из-за ООП?

(Я прошу прощения у LoveSan за офтопик и если мне сказано будет убраться, то я заведу другую тему. Просто тема была обычной закваской для очередного лиспосрача, а я попытался вместо этого обсудить интересное и полезное).

den73 ★★★★★
()
Ответ на: комментарий от den73

> как сделать подобно Паскалю (надо сказать, уже далеко не первая

попытка)


Еретик.

Интересно, а это разве не из-за ООП?


С ООП в CL таких проблем не возникает.

archimag ★★★
()
Ответ на: комментарий от archimag

> С ООП в CL таких проблем не возникает
Ну канешна. И ещё молочные реки с кисельными берегами.

den73 ★★★★★
()
Ответ на: комментарий от den73

> Я не еретик, а скорее печенег, явившийся разграбить храм сей.

Не, ты просто как-то неправильно используешь и имеешь кучу трабл из-за этого. Завязывай с паскалём, до хорошего он не доведёт ;)

Есть люди типа Дмитрия Иванова, респект им и уважуха, конечно.


А вот с ним у меня отношения как-то уж совсем не сложились, так что подписываться под этим не будут.

archimag ★★★
()
Ответ на: комментарий от archimag

> Не, ты просто как-то неправильно используешь и имеешь кучу трабл из-за этого.
Чем это не подходит под определение печенега? Печенег использует храм неправильно и при удачной обороне может поиметь траблы вплоть до летального исхода.

А вот с ним у меня отношения как-то уж совсем не сложились

Я говорю не про личность (лично только парой писем обменялся), а про достижения.

Завязывай с паскалём, до хорошего он не доведёт ;)

Тогда и с зарплатой придётся завязать, видимо. Паскаль - хороший язык. Уж точно лучше, чем С++. Т.е., на нём действительно можно программировать. Я сейчас подумываю, как бы встроить компилятор в runtime. Во всяком случае, есть интерпретаторы паскаля, в которые прекрасно биндятся все компоненты. Я даже поигрался с этим немного, выглядит перспективно. Однако, похоже, что с некоторыми ограничениями можно и нормальный компилятор встроить (по образу gcl/ecl, через разделяемые библиотеки). Для меня это было бы избавлением от основной боли Паскаля - невозможности итеративной разработки уже запущенной программы. Как в Лиспе, конечно, всё равно никогда не будет, но можно добиться неплохого приближения. Зато на Паскале можно писать программы реального времени без оговорок и он пролезает даже на самые мелкие платформы без большого урона.

den73 ★★★★★
()
Ответ на: комментарий от den73

> а про достижения.

А что за достижения такие особые?

Уж точно лучше, чем С++.


Спасибо, тема C++ vs Pascal была для меня актуальна лет 7 назад, я был (и остаюсь) не на стороне Pascal, но затевать разговор на эту тему больше не хочу. Хотя и честно думал, что паскаль уже окончательно похоронили.

archimag ★★★
()
Ответ на: комментарий от den73

я конечно понимаю, что у тебя много кода уже написано на CL.
Но интересно, а может быть схема подошла бы больше ?
тут вроде бы нормальные модули http://www.jazzscheme.org/tutorials.htm и какой-то жуткий ынтырпрайс http://www.jazzscheme.org/screenshots.htm  — эклиспа на схеме (Gambit, но переделанный)
вообще, было бы интересно от тебя услышать про scheme vs. cl для твоих задач.

anonymous
()
Ответ на: комментарий от archimag

> А что за достижения такие особые?
http://www.ystok.ru/
Человек сделал (видимо, стабильный) бизнес на CL, вот и достижения. С моей точки зрения, немало. Я мог в своё время сделать примерно так же, как он (я занимаюсь автоматизацией предприятий), но обосрался, а теперь, наверное, уже стал староват. И главное, я теперь не вижу в CL решающих преимуществ, чтобы идти этим путём.

Но интересно, а может быть схема подошла бы больше ?

Схема - она какая-то игрушечная, что ли. Я пробовал её не раз, но всё время утыкался в игрушечность и бросал. Например, важнейшая вещь - это keyword arguments. Её в Схеме отроду нет (не было на время смотрения), а прикрученное всегда хуже родного. Также важны continuable errors, а в схеме вроде такого понятия нет? Важны исключения, а в схеме вместо них call/cc, которое вообще позволяет всё вывернуть наизнанку и нарушить вложенность стека. Если там кто-то рекламирует что-то Ынтырпрайзное, то это пока что - только реклама. В реальных возможностях лиспа я уже на практике убедился и они меня устраивают для тех задач, которые я на него возлагаю (поддержка жизненного цикла СУБД, генерация различного кода, скрипты и конверторы).

den73 ★★★★★
()
Ответ на: комментарий от den73

Её в Схеме отроду нет (не было на время смотрения), а прикрученное всегда хуже родного.

Странно это читать, учитывая твои костыли вокруг отсутствия человеческих модулей.

anonymous
()
Ответ на: комментарий от den73

> Я не еретик, а скорее печенег,

язычнег!! вечно тебя готовые языки не устраивают :)

anonymous
()
Ответ на: комментарий от den73

> Я сейчас подумываю, как бы встроить компилятор в runtime. Во всяком случае, есть интерпретаторы паскаля, в которые прекрасно биндятся все компоненты.

у Луговского в MBase http://www.meta-alternative.net/mbase1.0beta6.zip есть паскалевский синтаксис в дотнете — это *.rl файлы в примерах.
Вообще судя по доке
http://www.meta-alternative.net/pfdoc.pdf http://www.meta-alternative.net/mbase1.0beta6.pdf  — MBase это компилятор DSL под .NET с PEG парсером + несколько встроенных синтаксисов (паскаль, .Net), генерирующий standalone .exe под .NET без лишних зависимостей.
Правда, ЕМНИП, не было манифестов под какую версию дотнета его конпелятор, поэтому что-то может не работать под конкретной версией, надо смотреть более свежие беты.
Я не знаю где раздают свежие беты MBase, наверно где-то в раёне оффсайта.

Ну а так, можно в принципе прикрутить ту же лисп/схему + PEG парсер паскаля и генерировать через C компилятор или LLVM+C, вопрос в том, как наиболее компактно это сделать

anonymous
()
Ответ на: комментарий от archimag

> Ну ты же его коверкаешь, конечно, не увидишь. Видимо, пора прекратить этот разговор, дабы никто не терял больше времени.

anonymous
()
Ответ на: комментарий от anonymous

den73

Во, Stella - это интересно, хотя мёртвый язык вызывает опасения. И такие эпические масштабы - не для меня. Вообще, мне более интересно встроить incremental development именно в саму программу на конечном языке и похоже, что это возможно в случае С и Паскаля, хотя ограничения и трудности будут.

anonymous
()
Ответ на: den73 от anonymous

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

archimag ★★★
()
Ответ на: комментарий от archimag

> Просто взял и переквалифицировался в веб-разработчика ибо это самый простой способ использовать CL на практике Ну, может и я там буду когда-нибудь. Хотя у меня давно нет пафоса именно «использовать CL». Скорее - есть стремление, чтобы вложенные в освоение CL силы не пропали зря. А какими инструментами и библиотеками пользуешься (лисповыми и не только)? Какого рода проекты реализуешь?

anonymous
()
Ответ на: комментарий от anonymous

> А какими инструментами и библиотеками пользуешься

(лисповыми и не только)?


http://github.com/archimag/
http://restas.lisper.ru/

Какого рода проекты реализуешь?


Да вроде уже много раз рассказывал:
http://lisper.ru/
http://www.youtube.com/watch?v=f6b0sQpDGVM

archimag ★★★
()
Ответ на: комментарий от archimag

Ну, за lisper.ru тебе вряд ли платят, что-нибудь есть из коммерческих проектов в вебе? Да и lisper.ru - ничего особенного, мне пришлось чуть-чуть поучаствовать в разработке https://github.com/lnostdal/SymbolicWeb - вот это было да!

То, что на видео - выглядит более интересно, но на сайте я про это мало что нашёл. Можно ли увидеть в вебе?

anonymous
()
Ответ на: комментарий от anonymous

> https://github.com/lnostdal/SymbolicWeb - вот это было да!

SymbolicWeb, как и большинство существующих веб-фреймворков для CL, это просто дурь какая-то.

То, что на видео - выглядит более интересно, но на сайте я про

это мало что нашёл. Можно ли увидеть в вебе?



В данный момент это внутри-корпоративная разработка, может быть через год будет в веб, а может и нет.

archimag ★★★
()
Ответ на: комментарий от archimag

den73

> В данный момент это внутри-корпоративная разработка, может быть через год будет в веб, а может и нет Ясно, жаль.

anonymous
()
Ответ на: комментарий от anonymous

> мне пришлось чуть-чуть поучаствовать в разработке https://github.com/lnostdal/SymbolicWeb - вот это было да!

ларс, конечно, клевый чувак, но то, что он делает далеко от промышленного программирования. И в частности symbolic web - это глубоко экспериментальный проект, который в реальной жизни не сможет выжить, потому что на нем будут хорошо и красиво писаться очень простые вещи, реальные приложения - криво и кособоко. Пихать те же шаблоны в лисп код - это безумие и показатель того, что человек никогда в своей жизни не писал в команде за деньги веб-приложения.

paranonymous
()
Ответ на: комментарий от paranonymous

den73

может быть и так. Я от веб-программирования далёк. Мне не понравилось в symbolicweb полная асинхронность и отсутствие каких-либо методов синхронизации. Я всего лишь хотел сказать, что уровень сложности и навороченности AJAX приложения намного выше, чем то, что я увидел на сайте у archimag-а.

Может быть, я что-то недопонимаю.

anonymous
()
Ответ на: den73 от anonymous

> Я всего лишь хотел сказать, что уровень сложности и навороченности AJAX приложения намного выше, чем то, что я увидел на сайте у archimag-а.

да ты верно шутишь, swchat сложнее форума с викой, подсветкой синтаксиса и рсс-аггрегатором?

paranonymous
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.