LINUX.ORG.RU

Сообщения monk

 

существует ли стабильный ABI для Qt?

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

Когда-то был qt-c. Потом был cpp-кусок от qtjambi. Вроде тоже помер. Сейчас смотрю, что в PyQt свой мегавелосипед (SIP — интерфейс из питона к C++), PerlQt — закончился в 2003 году, RubyQt — требует развернуть mingw.

Qt теперь снова только для С++ (и Python)?

 ,

monk
()

В чём делать шаблоны документов?

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

По ним есть утверждённые формы (шрифты, отступы, изображения...).

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

В связи с этим вопрос: в чём порекомендуете делать шаблоны? Под оффтопиком естественный выбор — офис, но OpenOffice не хочется — как-то не юниксвейно.

Пытаюсь выбрать между html и latex. Вроде latex лучше: результат всё равно ожидается только на печати, но в html проще с шрифтами, да и wysiwyg есть...

Ваши мнения?

 , ,

monk
()

Почему в scheme не любят set! ?

Может, кто-нибудь знает, почему в Scheme (и в Racket) не приянто использовать set!, особенно в списках

Например, если мне надо список разделить на два по «выполняется/не выполняется условие», то в CL это будет выглядеть как

(defun split (list pred)
  (let ((res1 nil) (res2 nil))
     (dolist (l list)
        (if (pred l)
            (push l res1)
            (push l res2)))
     (values (nreverse res1) (nreverse res2))))

На Scheme полный аналог

(define (split list pred)
  (let ([res1 null] [res2 null])
     (for-each (lambda (l)
                 (if (pred l)
                    (set! res1 (cons l res1))
                    (set! res2 (cons l res2))))
          list)
     (values (reverse res1) (reverse res2))))

Но в учебниках по Scheme пишут, что так писать очень плохо, а надо так:

(define (split list pred)
   (define (loop list res1 res2)
     (cond
       [(null? list) (values (reverse res1) (reverse res2))]
       [else
         (if (pred (car list))
             (loop (cdr list) (cons (car list) res1) res2)
             (loop (cdr list) res1 (cons (car list) res1)))]))
   (loop list null null))
,мол, это понятнее.

Помогите понять, в чём смысл?

 , ,

monk
()

Помогите сделать макрос красивым

Сделал, чтобы Racket мог создавать функции на основании их описания из GObjectIntrospection. Сейчас смотрю на то, что получилсоь и понимаю, что «настоящий программист может написать программу на ФортранеКоммон Лиспе на любом языке».

Задача стоит так: есть описание функции в виде описаний входящих и исходящих параметров (исходящие — значит по ссылке). _fun использовать нельзя, так как массив передаётся в FFI (и если исходящий, то собирается из) двух параметров: указатель + длина.

Прошу совета как сделать правильно. Сейчас build-function строит исходный текст подстановки макроса (в стиле defmacro), а затем build-ffi подтсавляет его в datum->syntax.

Если пытаться делать без datum->syntax, то вылазят две проблемы: что делать с локальными define'ами и как генерировать имена переменных. С другой стороны, надеюсь решить проблему с именаим параметров: у меня сейчас !arg — входящий параметр, %arg — он же, преобразованный в Си, &arg — указатель на него.

(define-syntax (define-gi-definer stx)
  (syntax-case stx ()
    [(_ id) #'(define-gi-definer id id)]
    [(_ id repository)
     (with-syntax ([string-rep (->string (syntax-e #'repository))])
       (repository-require (syntax-e #'string-rep))
       #'(define-syntax (id stx)
           (syntax-case stx ()
             [(_ object) 
              (with-syntax ([string-obj (->string (syntax-e #'object))])
                (hash-ref! instance-hash (cons string-rep (syntax-e #'string-obj)) 
                           (λ () (syntax-local-lift-expression 
                                  (build-ffi stx (syntax-e #'string-rep) (syntax-e #'string-obj))))))])))]))

(define-for-syntax (build-ffi stx rep obj)
  (define res (find-gi rep obj))
  (datum->syntax stx res))

(define (find-gi repository name)
  (define info (rep:find repository name))
  (unless info
    (raise-argument-error 'find-gi "name of object in repository" name))
  (define type (g-base-info-get-type info))
  (case type
    [(constant) (const-value info)]
    [(function) (build-function info)]))

(define (build-function info)
  (define %args (args info))
  (define (in-arg? arg) (memq (g-arg-info-get-direction arg) '(in inout)))
  (define (out-arg? arg) (memq (g-arg-info-get-direction arg) '(out inout)))
  (define (array-pos arg)
    (define type (g-arg-info-get-type arg))
    (if (eq? (g-type-info-get-tag type) 'array)
        (g-type-info-get-array-length type)
        -1))
  (define res-type-symbol (tag->symbol_type
                           (g-type-info-get-tag (g-callable-info-get-return-type info))))
  (define fun-type (append (list '_fun)
                           (for/list ([arg (in-list %args)])
                             (if (out-arg? arg) '_pointer ((tag->symbol_type
                                                            (g-type-info-get-tag (g-arg-info-get-type arg))))))
                           (list '-> res-type-symbol)))
  
  (define vector-lengths (for/list ([arg (in-list %args)] 
                                    #:when (> (array-pos arg) -1))
                           (list-ref %args (array-pos arg))))
  (define in-args (filter (λ (arg) (and (not (memq arg vector-lengths)) (in-arg? arg))) %args))
  (define out-args (filter out-arg? %args))
  (define ((prefix-name prefix) arg) (string->symbol (string-append prefix (g-base-info-get-name arg))))
  (define ref-name (prefix-name "&"))
  (define init-name (prefix-name "!"))
  (define parsed-name (prefix-name "%"))
  (define fun-args (for/list ([arg (in-list %args)]) 
                     (if (out-arg? arg)
                         (ref-name arg)
                         (parsed-name arg))))
  (define (array-of type-info) (g-type-info-get-tag (g-type-info-get-param-type type-info 0)))
  (define parse-exprs
    (for/fold ([define-parsed null])
      ([in-arg (in-list in-args)])
      (define type-info (g-arg-info-get-type in-arg))
      (define tag (g-type-info-get-tag type-info))
      (if (eq? (g-type-info-get-tag type-info) 'array)
          (cons `(define ,(parsed-name in-arg) (pvector-ptr ,(init-name in-arg) ,(tag->symbol_type (array-of type-info))))
                (if (> (array-pos in-arg) -1)
                    (cons `(define ,(parsed-name (list-ref %args (array-pos in-arg))) (pvector-length ,(init-name in-arg))) define-parsed)
                    define-parsed))
          (cons `(define ,(parsed-name in-arg) ,(init-name in-arg))))))
  (define-values (total define-outs set-outs out-refs)
    (call-with-values 
     (λ ()
      (for/fold ([sum 0] [define-outs null] [set-outs null] [out-refs null]) 
        ([out-arg (in-list %args)] #:when (out-arg? out-arg))
        (define type-info (g-arg-info-get-type out-arg))
        (define tag (g-type-info-get-tag type-info))
        (values (+ sum (ctype-sizeof (tag->_type tag)))
                (cons `(define ,(ref-name out-arg) ,(if (= sum 0) 'ptr `(ptr-add ptr ,sum))) define-outs)
                (if (in-arg? out-arg) 
                    (cons `(ptr-set! ,(ref-name out-arg) ,(tag->symbol_type tag) ,(parsed-name out-arg)) set-outs)
                    set-outs)
                (cond 
                  [(eq? tag 'array) 
                   (cons `(pvector ,(tag->symbol_type (array-of type-info)) 
                                   (ptr-ref ,(ref-name out-arg))
                                   ,@(if (> (array-pos out-arg) -1)
                                         (list `(ptr-ref ,(ref-name (list-ref %args (array-pos out-arg)))))
                                         null)) out-refs)]
                  [(not (memq out-arg vector-lengths)) 
                   (cons `(ptr-ref ,(ref-name out-arg) ,(tag->symbol_type tag)) out-refs)]
                  [else out-refs]))))
     (λ (sum l1 l2 l3) (values sum (reverse l1) (reverse l2) (reverse l3)))))
  `(let ([fun (get-ffi-obj ,(g-function-info-get-symbol info) #f ,fun-type)]) 
     (lambda ,(map init-name in-args)
       ,@parse-exprs
       ,@(if (> total 0)
             (append (list `(define ptr (malloc ,total)))
                     define-outs)
             null)
       ,(if (eq? res-type-symbol '_void)
            `(fun ,@fun-args)
            `(define res (fun ,@fun-args)))
       ,(if (eq? res-type-symbol '_void)
            `(values ,@out-refs)
            `(values res ,@out-refs)))))

Пример раскрытого макроса:
(let ((fun (get-ffi-obj "gtk_init" #f (_fun _pointer _pointer -> _void))))
   (lambda (!argv)
     (define %argv (pvector-ptr !argv _string))
     (define %argc (pvector-length !argv))
     (define ptr (malloc 8))
     (define &argc ptr)
     (define &argv (ptr-add ptr 4))
     (fun &argc &argv)
     (values (pvector _string (ptr-ref &argv) (ptr-ref &argc)))))

 , ,

monk
()

Интерпретация, компиляция, а это что?

Если транслятор преобразовывает программу:

input i
let j = i * 2;
print j

в

#include "set_val.h"
hash vars;
int main()
{
   input("i");
   set("j", mult(val("i"), 2);
   print(val("j"));
}

где set, mult и val определены как

void set(char *key, variant & val)
{
   set_hash(vars, key, val);
}

variant val(char *key)
{
   return get_hash(vars, key);
}

variant mult(variant a, variant b)
{
   variant c;
   assert(a.type == NUMBER && b.type == NUMBER);
   c.type = NUMBER;
   c.number = a.number * b.number;
}

а затем при помощи gcc получает бинарник, то этот весь процесс является компиляцией или интерпретацией?

 ,

monk
()

Помогите найти алгоритм построения поверхности из точек

Есть облако точек. Известно, что это поверхность сплошной фигуры. Существует ли алгоритм построения полигональной поверхности этой фигуры?

 ,

monk
()

FFI, сложные типы данных, как лучше?

Думаю по поводу того, как должен выглядеть идеальный FFI (foreign function interface) между языком со сборщиком мусора (например, лиспом) и Си.

Для простых типов всё хорошо. А вот что делать со строками, массивами и структурами?

Фактически варианта всего два: транслировать или оставлять указателем.

Вариант с трансляцией мне не нравится тем, что функция «изменить значение головы списка» превратится в «преобразовать весь список, изменить значение головного эдемента, преобразовать список обратно». Хотя видел решения с идеологией «транслировать всё». Например, cl-virgil.

Вариант «всё хранить указателями с тэгами» приводит к наличию в языке двух наборов типов. Строки языка и строки FFI, структуры языка и структуры FFI, массивы языка и массивы FFI. С разными функциями для работы с ними. Получаем протекающую абстракцию... вроде опять плохо.

Если кто-нибудь сталкивался с подобной проблемой, то по какому пути шли и почему?

 ,

monk
()

Как на макросах изобразить инстанциирование

Есть макрос, который должен создавать функцию.

(defmacro build (info) `(lambda ...))

Текст функции зависит от содержимого структуры info.

Где-то в коде он многократно вызывается с разными параметрами. Можно ли как-то сделать, чтобы он при первом запуске где-то создавал функцию, а при последующих только ссылался на неё? То есть нужен механизм, аналогичный инстанциированию шаблонов C++.

Есть какие-нибудь идеи, как сделать? Реализация лиспа (CL, Scheme, ...) не важна.

 , ,

monk
()

Вдруг кому надо. G-Object-Introspection для Common Lisp

Собственно, сабж: https://github.com/andy128k/cl-gobject-introspection

Документация есть. На простых примерах протестировано (HelloWorld в каталоге test)

 , ,

monk
()

Вычисления при компиляции в Racket

Есть ли простой путь замены CL-овского #. ?

Например, кусок кода

(case ftype
                   ((#.(keyword->g-type :enum)
                       #.(keyword->g-type :flags))
                    (convert-to-foreign value (g-type->lisp type)))
                   (#.(keyword->g-type :double)
                      (coerce value 'double-float))
                   (#.(keyword->g-type :float)
                      (coerce value 'single-float))
                   ((#.(keyword->g-type :int)
                       #.(keyword->g-type :uint)
                       #.(keyword->g-type :long)
                       #.(keyword->g-type :ulong)
                       #.(keyword->g-type :int64)
                       #.(keyword->g-type :uint64)) (round value))
                   (t value))

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

Могу вручную выполнить (keyword->g-type :uint), (keyword->g-type :long) и подставить в код результаты. Но будет пачка «магических чисел» в коде. Причём, если в следующей версии будут другие числа у ключевых слов, придётся как-то искать все места использования.

Что посоветуете?

 ,

monk
()

XPath: помогите описать путь

Хочу находить список объектов вида

<td>Сообщение:</td><td>(.*?)</td>

В смысле, нужно то, что в скобках.

Помогите написать правило XPath. Или хоть намекните, куда смотреть, чтобы на соседние ветки условие накладывать.

 ,

monk
()

Проверки во время компиляции.

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

Если неадекватно, то как правильно?

 , , ,

monk
()

имена экспортируемых функций в Racket

Как принято именовать экспортируемые функции в библиотеке.

Для CL, например, есть два варианта:

  • С префиксом: symbol-function, dllist-append
  • Без префикса (считается, что «префиксом» будет пакет): gtk:add, iterate:for

Согласно Google style guide предпочитается вариант без префикса.

----

В Racket без префикса получаем, например, невозможность одновременно импортировать racket/contract и ffi/unsafe (в обоих есть ->). Пакетов нет. Есть (require (prefix-in ...)), но требует дополнительных телодвижений от пользователя библиотеки.

И что будет, если в импортируемой библиотеке случайно перекрывается символ из racket? Программа, использующая этот символ молча ломается?

В общем, вопрос такой: есть какие-нибудь guidelines для именования символов библиотек?

 ,

monk
()

Откуда у Scheme такие макросы?

Существует ли книга, в которой написано, почему макросы в scheme такие странные.

Логика макросов CL понятна. Всё есть список, дальше программист сам разберётся.

Часть решений в Scheme тоже: гигиена по-умолчанию, паттерны.

Но зачем нужна отдельная от списка структура кода (syntax)? Почему этот syntax, будучи созданным внутри макроса не привязывается автоматически к строке, где был использован макрос (вместо #' #` приходится писать syntax/loc)?

 ,

monk
()

Как узнать откуда ошибка в DrRacket?

Есть программа. В ней кусок

(require "loadlib.rkt")
...
(define-gobject* g-type-name (_fun _ulong -> string))
...

Допустил опечатку. Вместо _string написал string. Проверка синтаксиса проходит без предупреждений. При загрузке получаю сообщение об ошибке

. . loadlib.rkt:46:8: ffi-call: contract violation
  expected: ctype?
  given: #<procedure:string>
  argument position: 3rd
  other arguments...:
   #<ffi-obj>
   '(#<ctype:uint32>)
   #f
   #f
   #f

В loadlib.rkt:46:8 находится определение макроса define-gobject*. Причём он распаковывается в команду (define-gobject g-type-name (_fun _ulong -> string) #:c-name g_type_name) и никаких ffi-call там нет.

Как добиться от Racket нормальных сообщений об ошибке? Как минимум, нужно место применения макроса, а не его определения. Угадывать по тексту ошибки, в каком именно определении функции неверный аргумент, удовольствие ниже среднего.

 

monk
()

Идентификаторы, как правильно переводить?

Предположим есть проект с русскоязычными программистами. OpenSource. GPL. Будет публичный.

Как лучше именовать идентификаторы процедур, таблиц, переменных.

  • По-русски. СУБД и язык поддерживают Unicode. Можно писать «SELECT Житель, Город FROM Население», if (РассчитатьНДФЛ(...)) и так далее.
  • Транслитом.
  • Полностью переводить: СтавкаНДС -> VATrate, РассчитатьНДФЛ -> CalculatePersonalTax ...

Как лучше и почему?

 стиль программирования

monk
()

Зачем нужна свобода 2?

Свобода 0, 1 — очевидно. Позволяет пользователю сделать продукт для себя более удобным. Свобода 3 — тоже. Если я внёс модификацию и она полезна, то я имею право показать, что я внёс.

Зачем свобода 2? RHEL и Mozilla её обходят. BolgenOS — порицается (хотя лицензия не нарушена). Найти разработчиков для свободного проекта почти невозможно, так как результат можно продать только один раз. Дальше продавать может покупатель. Соответственно, остаётся только заказная разработка или чистый for fun. Ну или писать так, чтобы можно было хорошо заработать на поддержке :-)

 

monk
()

В чём плюсы image-based разработки?

archimag сказал, что image-based разработка — для него основное достоинство Common Lisp. В варианте SLIME. То есть не формируем в конце исходники из образа, а меняем исходники и на каждом шагу чуть-чуть меняем образ.

Имхо, image-based заставляет смотреть на программу не как на результат компиляции файлов исходников, а как на живой REPL, который иногда можно подкрутить для получения результата.

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

С другой стороны, предполагаю, blub-парадокс. Поэтому хочу узнать, что же особенно хорошего в image-based разработке с точки зрения тех, кто считает image-based лучше чем file-based.

 , ,

monk
()

Снова макросы Racket

Пытаюсь использовать макрос

(define-syntax-rule (with-template ([var ...] [form ...] ...) body ...)
  (begin (define-syntax-rule (inner var ...) (begin body ...))
         (inner form ...) ...))

для описания пачки однотипных макросов

(with-template 
 ([src dst]
  [define-gi define-gi*]
  [define-gtk define-gtk*])
(define-syntax (dst stx)
  (syntax-case stx ()
    [(dst id params ...)
     (let ([new-id (string->symbol (string-replace (symbol->string (syntax-e #'id)) "-" "_"))])
       #`(src id params ... #:c-id #,new-id))])))

Получаю очень странную ошибку main.rkt:38:20: syntax: no pattern variables before ellipsis in template at: ... in: (begin (define...syntax-e (syntax id))) "-" «_»)))) (quasisyntax (src id params ... #:c-id (unsyntax new-id))))))))

При том, что

(define-syntax (define-gtk* stx)
  (syntax-case stx ()
    [(define-gtk* id params ...)
     (let ([new-id (string->symbol (string-replace (symbol->string (syntax-e #'id)) "-" "_"))])
       #`(define-gtk id params ... #:c-id #,new-id))]))
работает прекрасно

Что я ещё не понял про рэкетовские макросы?

 ,

monk
()

Scribble. Помогите понять

Пытаюсь написать документацию

#lang scribble/manual
@(require (for-label racket))

@title{GObject Introspection}

This is Gobject FFI. 

Usage example:

@racketblock[
(gi-ffi gtk "Gtk")
(let ([window (gtk 'window 'new)])
  (window 'show))
]

DrRacket в строке состояния пишет «+: contract violation expected: number? given: #f argument position: 1st other arguments...: 0»

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

Что делать?

 

monk
()

RSS подписка на новые темы