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 и рядом не валялся, особенно в плане производительности.

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

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

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

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



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

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

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



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

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

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

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

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

>Ну, во-первых, матрица в Ракете, насколкьо я знаю, отмаршалится в **float,
Это такой тонкий намек на то, что в схеме нету многомерных массивов?

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

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

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

(foo matr add-number 100.0)

add-number


И он каждый раз будет создавать новый коллбэк?

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

Может я вас не правильно понял, но ваша фраза

никому не нужна эффективность ценой отказа от привычных способов программирования

для меня звучит как: нахрена мне калькулятор, я на счетах посчитаю.

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

Ну и повадки у вас.

как писать прикладуху на CL

Головой думаем, руками пишем. Что из этого для вас трудно?

no-such-file ★★★★★
()
Ответ на: комментарий от paranonymous

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

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

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

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

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


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

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

Это такой тонкий намек на то, что в схеме нету многомерных массивов?

В #lang racket - нету, есть только в srfi и в каких-то учебных языках, по-моему.

Существенное отличие, правда, в том, что типы и их значения разделены.

Странно, я как раз заметил, что у тебя, в отличии от моего примера, намешано все подряд. Кстати, а этот твой колбек хотя бы можно вызывать из самого cl?

И он каждый раз будет создавать новый коллбэк?

Это зависит от параметра #:keep.

anonymous
()
Ответ на: 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 ★★★
()
Ответ на: комментарий от anonymous

>Странно, я как раз заметил, что у тебя, в отличии от моего примера, намешано все подряд.
?

Кстати, а этот твой колбек хотя бы можно вызывать из самого cl?

Да. Точно так же, как и любой другой указатель н функцию.

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

?

Вместо того, чтобы работать с будущим коллбеком как с обычной лисповой функцией вводится новая форма define-callback, причем аннотации типов к ней прилеплены. Не говоря о том, что это неудобно (если понадобится сделать коллбеком обычную функцию, то приходится переписывать _саму функцию_), нарушается динамическая суть лиспа - одна и та же функция может быть коллбеком с разными типами. В моей примере это решается просто - надо лишь написать еще один тип _mycall с нужным враппером, который и подставить в аннотации соответствующей foreign-функции, тебе же придется, видимо, писать еще один (define-callback ...)?

Да. Точно так же, как и любой другой указатель н функцию.

То есть если у нас была функция (defun yoba (...) ...) а потом нам пришлось сделать из нее коллбек (define-callback yoba ...) то со всеми вызовами (yoba ...), которые были ниже по коду, все нормально? Не придется заменять обычные вызовы на вызовы при помощи каких-либо специальных форм типа (call yoba ...) или чего-нибудь в этом роде?

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

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

тебе же придется, видимо, писать еще один (define-callback ...)?

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

Динамическая же суть лиспа у меня в библиотеках там, где можно, сохраняется - например методы COM-интерфейсов в Doors - обобщенные функции CLOS.

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

При чем тут сишный и нативный код? Тут все дело только в синтаксисе аннотаций типов для коллбека. У меня аннотации выносятся наружу, по-этому лисповый код, получается, отделен от кода, обеспечивающего связь с сишным. Ну и + в аннотациях же можно на ходу делать врапперы для аргументов/возвращаемого значения. Декомпозиция, короче говоря:

#lang racket
(require ffi/unsafe)

(define ffi-test (ffi-lib "ffi_test.dll"))

(define-syntax-rule (_mcall wrapper)
  (_fun #:keep #f (matrix m n param) :: 
        (matrix : (type: _pointer 
                         pre: wrapper))
        (m : _int) 
        (n : _int) 
        (param : (type: _pointer 
                        pre: (x => (ptr-ref x _float)))) 
        -> _void))

(define _mcall1 (_mcall (x => (cblock->vector x _float 16))))
(define _mcall2 (_mcall (x => (cblock->list x _float 16))))

(define (foo _callback)
  (get-ffi-obj 'foo ffi-test
               (_fun (matrix m n f param) ::
                     (matrix : (type: _pointer
                                      pre: (x => (vector->cblock x _float))))
                     (m : _int) 
                     (n : _int) 
                     (f : _callback) 
                     (param : (_ptr i _float)) 
                     -> _void)))

(define (add-number matrix m n param)
  (displayln
   (for*/list ([i (in-range m)]
               [j (in-range n)])
     (+ param (cond
                [(list? matrix) (list-ref matrix (+ i (* j n)))]
                [(vector? matrix) (vector-ref matrix (+ i (* j n)))])))))

(define matr `((4 4) ,(vector 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)))
(define v (vector 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))
(define l (list (vector 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)))

((foo _mcall1) v 4 4 add-number 100.0)
((foo _mcall2) v 4 4 add-number 100.0)

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

Да, еще - как там с коллбеком лямбд дела обстоят? И как на счет существующих вызовов при переделывании обычной функции в коллбек?

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

Лисповские функции у меня в коллбэки не маршалятся автоматически, по нескольким серьезным причинам.

Но, если приперло, то некий конкретный пользователь библиотеки вполне может сделать себе тип типа (callback rtype &rest arg-types)и соответствующие трансляторы/конвертеры.

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

конкретный пользователь библиотеки вполне может сделать

Конкретный пользователь лиспо-библиотеки может сделать все, что угодно - это известный факт. В общем, как я понял, с лямбдами, юниморфностью и декомпозицией все обстоит хуже, чем очень плохо. Ну а что на счет сишных структур? Можно так хотя бы?

foo.so:

typedef struct { int x; char y; } A;
  
  A* makeA() {
    A *p = malloc(sizeof(A));
    p->x = 1;
    p->y = 2;
    return p;
  }
И потом делаем:
(define-cstruct _A ([x _int] [y _byte]))
  (define makeA
    (get-ffi-obj 'makeA "foo.so"
      (_fun -> _A-pointer))) ; using _A is a memory-corrupting bug!

(define a (makeA))
Дальше предикаты, сеттеры/геттеры создаются автоматически:
> (list a (A? a) (A-x a) (A-y a))
'(#<cpointer:A> #t 1 2)

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

Со структурами все отлично. Более того, структуры используются лисповские, а не какие-нибудь вонючие [врапперы над] cpointer.

Правда, по последней же причине, в случае со структурами которые должны обязательно существовать в памяти [и сохранять identity по указателю] между вызовами сишных функций, придется таки хранить их в лиспе как тупые указатели, и время от времени использовать макрос with-value с :inout параметром.

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

;;обычная DEFSTRUCT-структура, плюс немного метаинформации о типах
(define-struct a
  (x int) (y byte)) ;;если бы char, то Y на лисповской стороне представлялся бы как character

(define-external-function
    ("makeA" (:camel-case))
    (:cdecl libfoo)
  (void rv output)
  (output (& a :out) :aux))

;;(make-a)
;;==> #S(A :X 1 :Y 2)
;;(a-x *)
;;==> 1
;;(a-y **)
;;==> 2

Единственно, пока что Virgil не умеет передавать(и возвращать) агрегированные структуры данных по значению.

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

Со структурами все отлично. Более того, структуры используются лисповские, а не какие-нибудь вонючие [врапперы над] cpointer.

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

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

они боятся скобок :) все языки стырившие из лиспа всё что только можно (включая _всё_) процветают. даже языки стырившие только часть --- процветают!

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

но чуть погодя любой кто пишет на тянутом с лиспа языке начинает понимать что ему не хватает именно скобок + всё что они дают...

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

это может даже быть на уровне eDSL имитирующего операторы распространённого тянутого языка. Пока на такой «педагогический эксперимент» сил (коварности) не у кого не хватило.

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

> они боятся скобок :)

порог вхождения оказывается решающим


Ты, естественно, не поверишь, но далеко не все разработчики (включая разработчиков прикладных программ) являются идиотами, мало того, идиотов среди них как раз очень мало.

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

они _сразу_ рождаются лысыми и с искривленными клавиатурой пальцами?

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

я знаю что это поможет не всем «идиотам», стать «не идиотами» (лисп не настолько всесилен :), но жизнь _не_идиотов станет значительно легче.

впрочем ты как всегда ничего не понял :)))

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

> не могут сделать сознательный вывод в свою же пользу (ну выбрать

правильный язык программирования :).


Писать хороший прикладной софт могут, а сделать выбор языка нет? Это что, настолько сложнее? Если большинство разработчиков выбирают не CL, а другой язык, то нельзя говорить что это проблемы разработчиков, а это однозначно проблемы CL и отражение существующих с ним проблем, и нельзя сказать что эти проблемы не объективны.

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

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

загрузил модуль «пролог» --- имеешь операторы пролога, загрузил питон --- «питон».

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

и кстате в торенте тянут книжку «объектно-ориентированное программирование в лисп» что дурные... остальные книжки как то не очень.

вот такого медку подсыпать, и народ действительно тянется :)

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

> дык написал же, порог входа высок... надо было им к пользователю выпятить всякие итерате с лопами

Нехватает нормальных, production качества, библиотек. Из тех что есть половина наколенные поделки, а вторая часть пишется одним - двумя людьми, которые частенько забивают на патчи и запросто могут сломать совместимость между версиями прямо в текущей ветке Git'а. Плюс все не любят писать доки (тут я их понимаю). Даже врапперы как правило коцанные и не поддерживают всех возможностей нижележащей библиотеки - как пример можно сравнить CommonQt и QtRuby/Korundum.

Это основная проблема CL - батареек не хватает.

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

Каких конкретно библиотек тебе не хватило? Или в каких библиотеках не хватило возможностей(«коцаные»)?

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

Если Qt, то Qt - чисто плюсовое поделие, и для CL не нужно.
Для гуйни можно cl-gtk2

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

> Каких конкретно библиотек тебе не хватило?

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

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

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

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

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

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