LINUX.ORG.RU

Сообщения den73

 

golang: одноимённые методы в разных интерфейсах

Форум — Development

Вопрос 1

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

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

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

Мои действия в golang?

Вопрос 2 (он про Яр, конечно же)

Есть билиотека ::словари::, в ней есть тип контейнер, и у него метод контейнер%дай(строка). По соглашению, если ц - типа контейнер, то ц.дай превращается в контейнер%дай(ц). Т.е. примерно то же, что утиная интерфейсизация в golang, только интерфейс в данном случае состоит из одной функции. Я это придумал никак не глядя на голанг, а всего лишь пытаясь сделать костыль для неудобного обращения в лиспе к полям структур.

В библиотеке ::словари:: есть также generic код:

опр функ Напечатай-все-значения(о) тело
  для каждого ключа к (о) // мифический синтаксис
    л-печать(о.дай(к))
  кнд кно
Мы здесь экономим то, что у нас вообще не вводится понятие интерфейса. В голанге так сделали, я их понимаю и считаю, что это круто. Иногда утиная интерфейсизация - это круто. Более того, если эту функцию сделать inline, то она будет при известном типе о подставлять сразу соответствующий-контейнер%дай, а при неизвестном - будет динамически искать соответствующую данному типу функцию *%дай.

Но это - мина, которая позже рванёт.

Также есть (чужая) библиотека «рефлексия», в ней есть тип рефлексирующий-субъект, у которого тоже есть рефлексирующий-субъект%дай(строка), но по смыслу это означает «дай метаинформацию такого-то типа».

И теперь мы делаем рефлексивный словарь. И оказываемся в тупике, т.к. нам нужно сделать две функции рефлексивный-словарь%дай с разным смыслом.

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

 

den73
()

кто понимает ковариантность?

Форум — Development

Просмотрел три статьи про вариантность, во всех неточности или ошибки:

https://ru.wikipedia.org/wiki/Ковариантность_и_контравариантность_(программир...

Статья неверна в принципе, начиная с определений:

Ковариа?нтность и контравариа?нтность[1] в программировании — способы переноса наследования типов на производные[2] от них типы — контейнеры, обобщённые типы, делегаты и т. п.

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

Если мы просто передаём параметр, List<Cat> там, где от нас ждут List<T extends Animal>, то мы можем подставить List<Cat> «вместо» List<Animal>, но при этом List<Cat> не становится потомком List<Animal>. Т.е., иерархии никакой нет, а есть заменимость типов в конкретном контексте.

Далее, если мы просто пишем Animal *А = new Cat(), то я бы это тоже рассмотрел как ковариантность, хотя здесь нет никаких производных иерархий. Точно так же, здесь есть подстановка одного вместо другого, я бы назвал это «тривиальным» или «единичным» случаем вариантности. Хотя, конечно, о терминах не спорят - их просто принимают. Но если мы говорим о натуральных числах, то логичнее включить в определение единицу, а не начинать их с двойки.

http://habibutsu.github.io/variance.html - для С++ ошибка в том, что говорится «нужно было С», или «нужно было А», в то время как правильно будет «нужно было B или C» или «нужно было B или А»

http://boyarincev.net/2014/09/covariance-and-contrvariance-in-c-sharp/

В контравариантности путаница (неправильно объяснено).

И т.д.

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

**********************

Вариантность - это возможность использовать подтип Пт вместо супертипа Ст или наоборот, в ряде частных случаев:

  • в место, типизированное как Ст, можно записать Пт
  • в место, типизированное как функция(Пт), можно записать функцию типа функция(Ст). В место, типизированное как функция() — Ст, можно записать функцию типа функция() — Пт
  • если типизированный контейнер Конт<T> только читается из места, типизированного как Конт<Ст>, то можно записать в него Конт<Пт> (в C# и в Java такая возможность замены требует особого указания в сигнатуре места). Если в него только пишется, то в место, типизированное как Конт<Пт>, можно записать Конт<Пт>
  • если виртуальная функция принимает Пт, то её можно перекрыть в потомке так, что она будет принимать Ст. Если ф-я возвращает Ст, то её можно перекрыть, чтобы она возвращала Пт.
  • если запись з1 отличается от записи з2 только тем, что поле з1.П1 - типа Пт, а з2.П1 - типа Ст, то з1 - подтип з2.

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

Инвариантность - это просто отсутствие ко- или контра-вариантности, т.е. отсутствие предмета обсуждения как такового.

**********************

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

А вот предыдущая тема про это: Ковариантность и динамическая типизация

 , , , , ковариантность

den73
()

Индексирование частично упорядоченного множества

Форум — Development

В частично упорядоченном множестве хочу быстро узнавать, верно ли, что А<Б. Видимо, для этого надо построить какой-то индекс и пользоваться им. Какой? Как его быстро построить?

Пока нашёл вот это: http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.88.6760&rep=rep1... но даже не смотрел. Мне кажется, это должно быть в каком-то учебнике, который я не читал.

 

den73
()

Ищутся статически типизированные контейнеры для Common Lisp

Форум — Development

Например, аналог Map<T1,Т2> с интеграцией в систему типов SBCL, чтобы можно было выкинуть проверки, когда тип известен во время компиляции?

 ,

den73
()

Ковариантность и динамическая типизация

Форум — Development

Согласно принципу Лисков, экземпляр подтипа должен вести себя так же, как экземпляр супертипа. И вот у нас Keyboard - подтип Device, мы делаем какой-нибудь List<Device> (как бы супертип) и List<Keyboard> (как бы подтип).

Но на самом деле нет. Если мы рассмотрим полную сигнатуру функции «добавить» с учётом динамической типизации, то оказывается, что попытка вставить Mouse в List<Keyboard> имеет определённое поведение, отличающееся от такового для List<Device>. В первом случае будет ошибка времени выполнения (некорректный тип), а во втором мышь вставится в список.

Т.е. здесь нет ковариантности.

А теперь вопрос: что используется в ковариантности в языках, позволяющих скомпилировать код, вставляющий «нечто» (any,variant,t) в такой вот «псевдоковариантный» контейнер.

Мне кажется, должен быть какой-то костыль для этой ситуации, и я подозреваю, что он может присутствовать в Scala и/или в C#. Кто может что-нибудь сказать?

 ,

den73
()

Сравнение быстродействия виртуальных методов С++ и CLOS

Форум — Development

Было бы интересно сравнить производительность вирт. функций.

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

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

Код такой, но за качество не ручаюсь. Добровольцы на code review приглашаются.

;; clos-virtual-method-benchmark.lisp
(in-package :cl-user)

(declaim
 (optimize (speed 3) (safety 0) (debug 0)
           (space 0) (compilation-speed 0)))

(proclaim
 '(optimize (speed 3) (safety 0) (debug 0)
           (space 0) (compilation-speed 0)))


(defparameter *times* (* 100 1000 1000))

(defstruct base 
  next
  )

(defstruct (test-class-3 (:include base))
  fld1
  fld2
  )

(declaim (sb-ext:maybe-inline Делишко+))
(proclaim '(sb-ext:maybe-inline Делишко+))

(declaim (inline Делишко+))
(proclaim '(inline Делишко+))

(defgeneric Делишко+ (ц))

(defmethod Делишко+ ((ц base))
  7)

(defmethod Делишко+ ((ц test-class-3))
  (setf (test-class-3-fld1 ц) (test-class-3-fld2 ц))
  1)

(defmethod Делишко+ ((ц string))
  0)

(defun inner (o n)
  (declare (type fixnum n))
  (declare (type base o))
  (declare (inline Делишко+))
  (let ((res 0))
    (declare (type fixnum res))
    (dotimes (i n)
      (incf res (the fixnum (Делишко+ o)))
      (incf res (the fixnum (Делишко+ o)))
      (incf res (the fixnum (Делишко+ o)))
      (incf res (the fixnum (Делишко+ o)))
      (incf res (the fixnum (Делишко+ o)))
      (incf res (the fixnum (Делишко+ o)))
      (incf res (the fixnum (Делишко+ o)))
      (incf res (the fixnum (Делишко+ o)))
      (incf res (the fixnum (Делишко+ o)))
      (incf res (the fixnum (Делишко+ o)))
      (setf res (mod res 16))
      (setf o (base-next o)))
    (print res)
    res))

(defun main()
  (let* (
         (o1 (make-test-class-3 :fld1 1))
         (o2 (make-test-class-3 :fld1 1 :next o1))
         res)
    (setf (test-class-3-next o1) o2)
    (setf res (inner o1 *times*))
    (format t "~%~S~%" res)))

(let ((*trace-output* *standard-output*))
  (time (main)))

;; eof
6.7 секунды

С++

// cpp-virtual-method-benchmark.cpp
#include "stdio.h"
#include <cstdlib>

class base_class {
public:
        base_class* next;
        virtual int meth() { return 0; };
};

class test_class : public base_class {
public:
	int fld1, fld2, fld3, fld4, fld5;
        int meth () { fld4 = fld2; return 1; };
};


int inner(base_class *o,int bound) {
    int res=0;
    for (int i=0;i<bound;i++) {
        res += o->meth();
        res += o->meth();
        res += o->meth();
        res += o->meth();
        res += o->meth();
        res += o->meth();
        res += o->meth();
        res += o->meth();
        res += o->meth();
        res += o->meth();
        o = o->next;
        res = res % 16;

    }    
    return res;
}

int main(int argc, char* argv[])
{
    test_class o1;
    test_class o2;
    o1.fld1=1;
    o2.fld1=1;
    o1.next=&o2;
    o2.next=&o1;
    int n = 100*1000*1000;
    int result=inner(&o1,n);
    printf("%d %d\n",o1.fld5,result); // проверяем корректность и чтобы оптимизатор
    // не выкинул неиспользуемый код
    return 0;
}

// g++ -O2 -o cpp-benchmark cpp-virtual-method-benchmark.cpp ; echo disassemble inner | gdb cpp-benchmark ; time ./cpp-benchmark 
1.54 секунды.

Ну и для полноты картины, создаваемая объектная система для Яра:

  • Полностью оптимизирована под отладку, смещение в VMT выражено глобальной переменной, вызов функции через символ - 31 секунда.
  • то же, но вызов функции как функции 16 секунд
  • то же, оптимизация под скорость - 4.2 секунды

Получилось в 1.6 раза быстрее CLOS и в 2.7 раз медленнее С++. Правда, для множественной диспетчеризации скорее всего проиграем против CLOS. С другой стороны, сделать inline статический диспатч для CLOS методов в случае, когда тип достаточно хорошо известен, мне не удалось, оно делается с помощью MOP. Я делаю примерно то же, но без CLOS.

 ,

den73
()

кортежи не нужны?

Форум — Development

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

struct gasket {
    float weight;
    unsigned height;
    unsigned diameter;
};
 
void main() {
    struct gasket obj = { 12.f, 120, 30 };

Можно вернуть структуру из функции, можно передать в функцию. Спрашивается, а зачем тогда кортежи? Что нового они вообще дают хоть в каком-то языке? Понятно, что в языках, где список может состоять из элементов только одного типа, и где нет типа any/t/variant, кортежи могут быть кривым костылём для полиморфных списков. Ну и теоретически они могут быть эффективнее. Но Си всё равно даёт то же самое, плюс поля кортежа ещё и именованные. Единственное неудобство - это то, что тип структуры нужно объявлять. Но в этом можно видеть плюс, т.к. объявление структуры заставляет дать вещам имена и тем самым сделать программу более явной и понятной. А типизация полей структуры убережёт от ошибок.

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

Что я упустил?

 

den73
()

Как в Хаскеле сделать try..catch..finally?

Форум — Development

Как написать вот это:

зайти-в-сарай()
try
  ткнуть-палкой-в-осиное-гнездо-в-сарае()
catch all
  вернуть "Ой"
end

и вот это:

зайти-в-сарай()
try
  ткнуть-палкой-в-осиное-гнездо-в-сарае()
finally
  уходя-из-сарая-погасить-свет()
end

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

 ,

den73
()

За какую зарплату вы согласились бы фулл-тайм программировать на Common Lisp?

Форум — Talks

Это не предложение о работе. Это просто вопрос. Прежде всего, вопрос обращён к тем, кто знает лисп, а не к школьникам, которые просто хотят много зарабатывать.

Перемещено jollheef из job

 ,

den73
()

Транслятор подмножества Common Lisp в GLSL

Форум — Development

https://github.com/cbaggers/varjo

1500 коммитов за 4 года, два контрибюьтора.

  • Поддерживает макросы, в т.ч. define-compiler-macro
  • Статическая типизация
  • multiple-values
  • defstruct
  • ограниченная поддержка ф-й первого класса (функции должны быть разрешены статически)
  • inline GLSL expressions
  • WIP for declare and extensible declaration identifiers
  • проверка типов внутри и между этапами шейдинга

Остальное не понял.

> (ql:quickload :varjo)

 ,

den73
()

относительно живой проект по улучшению документации Common Lisp

Форум — Development

 

den73
()

Сравнение производительности доступа к полям структур в Python, Common Lisp и С++

Форум — Development

Помните, я сказал, что постараюсь не писать до конца сентября? Так вот: у меня не получилось :) Кому не нравится тут тег Яр - заверяю, что он не для рекламы (и так все уже знают), а исключительно для удобства: мне по нему удобно искать, а вам его удобно заигнорить. Отношение к Яру здесь такое: я мучаюсь, как мне реализовать объекты Яра. Склоняюсь к тому, что сделать их с опцией «реализовать как defstruct/clos». Но дальше идут тонкости, в которые сейчас не лезу.

Итак, я нашёл тред пиписькометрии 7 - летней давности: https://www.linux.org.ru/forum/development/4535326, и там сравнивалась скорость каких-то циклов. но это неинтересно. Интересно сравнивать скорость доступа к полям объектов хотя бы. Я попробовал. Вот что в итоге вышло (платформа 64 разрядная).

С++

// cpp-benchmark.cpp
#include "stdio.h"
#include <cstdlib>

class test_class {
public:
	int fld1, fld2, fld3, fld4, fld5;
        test_class *next;
};


int inner(test_class *o,int bound) {
    int res=0;
    for (int i=0;i<bound;i++) {
        res += o->fld1;
        o->fld2 = o->fld1;
        o->fld3 = o->fld2;
        o->fld4 = o->fld3;
        o->fld5 = o->fld4;
        o->fld1 = res - 1;
        o = o->next;
        res = res % 16;

    }    
    return res;
}

int main(int argc, char* argv[])
{
    test_class o1;
    test_class o2;
    o1.fld1=1;
    o2.fld1=1;
    o1.next=&o2;
    o2.next=&o1;
    int n = 100*1000*1000;
    int result=inner(&o1,n);
    printf("%d %d\n",o1.fld5,result); // проверяем корректность и чтобы оптимизатор
    // не выкинул неиспользуемый код
    return 0;
}
// EOF
// запускаем:
g++ -O2 -o cpp-benchmark cpp-benchmark.cpp ; echo disassemble inner | gdb cpp-benchmark ; time ./cpp-benchmark 
// листинг пропускаю.

real	0m0.225s
user	0m0.216s
sys	0m0.004s

Лисп на структурах:

;; struct-benchmark.lisp
(in-package :cl-user)

(list
 '#.(restrict-compiler-policy 'safety)
 '#.(restrict-compiler-policy 'debug))
 
(declaim
 (optimize (speed 3) (safety 0) (debug 0)
           (space 0) (compilation-speed 0)))

(defparameter *times* (* 100 1000 1000))

(defstruct test-struct 
  (next nil :type (or null test-struct))
  (fld1 0 :type fixnum)
  (fld2 0 :type fixnum)
  (fld3 0 :type fixnum)
  (fld4 0 :type fixnum)
  (fld5 0 :type fixnum)
  )

(declaim (inline test-struct-fld1 test-struct-fld2 test-struct-fld3 test-struct-fld4 test-struct-fld5 (setf test-struct-fld1) (setf test-struct-fld2) (setf test-struct-fld3) (setf test-struct-fld4) (setf test-struct-fld5)
                    test-struct-next))

(defun inner (o n)
  (declare (type test-struct o))
  (declare (type fixnum n))
  (let ((res 0))
    (declare (type fixnum res))
    (dotimes (i n)
      (incf res (the fixnum (test-struct-fld1 o)))
      (setf (test-struct-fld2 o) (test-struct-fld1 o)
            (test-struct-fld3 o) (test-struct-fld2 o)
            (test-struct-fld4 o) (test-struct-fld3 o)
            (test-struct-fld5 o) (test-struct-fld4 o)
            (test-struct-fld1 o) (- res 1)
            o (test-struct-next o)
            res (mod res 16)))
    res))

(defun main ()
  (let* ((o1 (make-test-struct :fld1 1))
         (o2 (make-test-struct :fld1 1 :next o1))
         res)
    (setf (test-struct-next o1) o2)
    (setf res (inner o1 *times*))
    (format t "~S~%~S~%" (test-struct-fld5 o1) res)))

(let ((*trace-output* *standard-output*))
  (time (main)))
;;;; EOF
;; запускаем
>(load (compile-file "~/py/struct-benchmark.lisp"))
  0.394 seconds of real time
  0.436000 seconds of total run time (0.436000 user, 0.000000 system)
Лисп, но вместо inline ставим notinline - все аксессоры превращаются в полноценные функции. Получаем
real time 3.879 seconds
Лисп на CLOS:
;; clos-benchmark-with-types.lisp
(in-package :cl-user)

(list
 '#.(restrict-compiler-policy 'safety)
 '#.(restrict-compiler-policy 'debug))
 
(declaim
 (optimize (speed 3) (safety 0) (debug 0)
           (space 0) (compilation-speed 0)))

(defparameter *times* (* 100 1000 1000))

(defclass test-class-3 ()
  ((fld1 :initarg :fld1 :accessor test-class-3-fld1)
   (fld2 :accessor test-class-3-fld2)
   (fld3 :accessor test-class-3-fld3)
   (fld4 :accessor test-class-3-fld4)
   (fld5 :accessor test-class-3-fld5)
   (next :initarg :next :accessor test-class-3-next)))

(defun inner (o n)
  (declare (type fixnum n))
  (declare (type test-class-3 o))
  (let ((res 0))
    (declare (type fixnum res))
    (dotimes (i n)
      (incf res (the fixnum (test-class-3-fld1 o)))
      (setf (test-class-3-fld2 o) (the fixnum (test-class-3-fld1 o))
            (test-class-3-fld3 o) (the fixnum (test-class-3-fld2 o))
            (test-class-3-fld4 o) (the fixnum (test-class-3-fld3 o))
            (test-class-3-fld5 o) (the fixnum (test-class-3-fld4 o))
            (test-class-3-fld1 o) (the fixnum (- res 1))
            o (test-class-3-next o)
            res (mod res 16)))
    (print res)
    res))

(defun main()
  (let* (
         (o1 (make-instance 'test-class-3 :fld1 1))
         (o2 (make-instance 'test-class-3 :fld1 1 :next o1))
         res)
    (setf (test-class-3-next o1) o2)
    (setf res (inner o1 *times*))
    (format t "~S~%~S~%" (test-class-3-fld5 o1) res)))

(let ((*trace-output* *standard-output*))
  (time (main)))
#|
6.115секунд
|#

python:

# ~/py/oop-benchmark.py
import time

__times__ = 100*1000*1000

class TestClass3(object):
  
    def __init__(self):
        self.fld1 = 1
        self.fld2 = 0
        self.fld3 = 0
        self.fld4 = 0
        self.fld5 = 0
        self.next = self

def inner(o,count):
    res = 0
    for i in xrange(count):
        res += o.fld1
        o.fld2 = o.fld1
        o.fld3 = o.fld2
        o.fld4 = o.fld3
        o.fld5 = o.fld4
        o.fld1 = res - 1
        o = o.next;
        res = res % 16
    return res

def my_main():
    o1 = TestClass3()
    o2 = TestClass3()
    o1.next = o2
    o2.next = o1
    res = inner(o1,__times__)
    print '%s' % o1.fld5
    print '%s' % res

my_main()

# запуск:
#time python oop-benchmark.py 
#266666656
#3
#real	0m51.031s
#user	0m50.696s
#sys	0m0.052s
FreePascal
{oop-benchmark.fpc}
{$mode ObjFPC}
const n=100*1000*1000;
type
  PTest = ^TTest;
  TTest = object
  public
    fld1, fld2, fld3, fld4, fld5: Integer;
    next: PTest;
  end;

function inner(o: PTest; bound: Integer): Integer;
var i: Integer;
begin
  Result:=0;
  for i:=0 to bound-1 do with o^ do begin
    Result:=Result+fld1;
    fld2:=fld1;
    fld3:=fld2;
    fld4:=fld3;
    fld5:=fld4;
    fld1:=Result-1;
    o:=next;
    Result:=Result mod 16;
  end;
end;

var
  o1, o2: TTest;
  b: Integer;
begin
  o1.fld1:=1; o1.next:=@o2;
  o2.fld1:=1; o2.next:=@o1;
  b:=inner(@o1,n);
  WriteLn(o1.fld5,' ',b);
end.
{

fpc -O3 oop-benchmark.fpc
Free Pascal Compiler version 2.6.4+dfsg-4 [2014/10/14] for x86_64
Copyright (c) 1993-2014 by Florian Klaempfl and others
Target OS: Linux for x86-64
Compiling oop-benchmark.fpc
Linking oop-benchmark
/usr/bin/ld.bfd: warning: link.res contains output sections; did you forget -T?
36 lines compiled, 0.1 sec 
1 warning(s) issued
den73@deb8:~/py$ time ./oop-benchmark
266666656 3

real	0m1.810s
user	0m1.776s
sys	0m0.008s
}

cython, pypy

##########
# test.pyx file

import cython

cdef class TestClass:

    cdef public unsigned int fld1, fld2, fld3, fld4, fld5
    cdef public object next
    
    def __cinit__(self):
        self.fld1 = 1
        self.fld2 = 0
        self.fld3 = 0
        self.fld4 = 0
        self.fld5 = 0
        self.next = self

@cython.overflowcheck(False)
@cython.cdivision(True)
cdef inner(TestClass o, count):
    cdef unsigned int res = 0, i
    for i in range(count):
        res += o.fld1
        o.fld2 = o.fld1
        o.fld3 = o.fld2
        o.fld4 = o.fld3
        o.fld5 = o.fld4
        o.fld1 = res - 1
        o = o.next;
        res = res % 16
    return res

def main():
    cdef TestClass o1, o2
    o1 = TestClass()
    o2 = TestClass()
    o1.next = o2
    o2.next = o1
    res = inner(o1, 100_000_000)
    print('%s' % o1.fld5)
    print('%s' % res)

##########
# setup.py file

from distutils.core import setup
from distutils.extension import Extension
from Cython.Build import cythonize

# to compile a module:
# python setup.py build_ext --inplace

extensions = [
    Extension('test', ['test.pyx'],
              extra_compile_args=['-O3'])
]

setup(name = 'access attrs benchmark',
      ext_modules = cythonize(extensions, annotate=True),
)

#########
# main.py file

from test import *
main()

# Запуск с помощью pip 
# 1. Создать ТРИ файла, исходник которых дан выше
# 2. В этой директории:
python setup.py build_ext --inplace
time python main.py

# Результаты:
real	0m0.306s
user	0m0.304s
sys	0m0.004s

$ time pypy oop-benchmark.py 
266666656
3

real	0m0,761s
user	0m0,736s
sys	0m0,020s

EMACS Lisp - несколько быстрее Питона.

 , cоmmon lisp, , ,

den73
()

ура, наконец-то в Яре достигнут какой-то успех

Форум — Development

Сбылась мечта идиота - я почти сделал из лиспа дельфи :) Кое-что недопилено, конечно, но в целом результат вполне прощупывается:

опр функ Foo(SYM -- :л:CL.SYMBOL)
тело
  л-печать(SYM.NAME())
  зап SYM.VALUE = 6
  л-печать(SYM.VALUE)
кно

Foo(цит(б))
Этот код транслируется примерно в такой код лиспа (на самом деле, дословно он генерируется далеко не такой, но если писать то же самое вручную, то был бы такой).
(declaim (ftype (function (SYMBOL ) t) |Foo| ))
(proclaim '(ftype (function (SYMBOL ) t) |Foo| ))

(defun |Foo| (SYM)
  (declare (type SYMBOL SYM))
  (PRINT (symbol-name sym))
  (setf (symbol-value sym) 6)
  (PRINT (symbol-value sym)))

(|Foo| (QUOTE |б|))

Итак, что я наконец-то получил? Конечно, пример маленький и не во всём показателен, но:

1. Общее количество букв уменьшилось ВДВОЕ.

2. Количество скобок уменьшилось более чем ВЧЕТВЕРО.

3. Количество повторений слова symbol уменьшилось в ШЕСТЬ раз. Символ здесь, как вы понимаете, моделирует какой-то defstruct - а структуры я пока что в Яр не впилил.

4. Лисп, чувствительный к регистру символов, без вертикальный чёрточек.

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

Вот, собственно, что я собирался сделать месяца за два летом 2015-го года. Надо было сразу перевести в следующую единицу измерения, и получилась бы правильная оценка трудоёмкости.

Что теперь я ожидаю от лисперов: я ожидаю, что они будут меня ругать. Написанный здесь код - это сумма множества предварительных этапов. Я публиковал свои решения на каждом этапе, и на каждом этапе меня ругали. Меня называли психом, блюб программистом и прочими другими плохими словами. Теперь настоящие лисперы должны просто лопнуть от злости. Хорошо лишь то, что их почти не осталось.

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

 ,

den73
()

Замыкания, С++ и память

Форум — Development

Да простит мне публика ламерский вопрос. Вот в С++ есть замыкания. Я немного почитал про них, но всё равно не уверен, что понял.

Вот например

Я правильно понял, что closure object может присваиваться только копированием? И что если мы хотим, чтобы гигантские захваченные данные не копировались, мы должны решать это сами, захватывая такие ссылки объекты, которые реализуют нужное нам поведение с т.з. времени жизни? Просто я давно отстал от мира С++ и мне аж страшно на это всё смотреть.

 , ,

den73
()

Где можно обращаться к предпоследнему элементу списка как List(END-1) ?

Форум — Development

Получить предпоследний элемент списка:

lindex {1 2 3 4} end-1

Питон:

some_list[-2]
В Перле подобное же.

Если сравниваем, то видим, что python и Перл - это кака, а tcl - конфетка. Проблемы питона: а вдруг я не имел в виду индекс с конца, а просто ошибся и неправильно вычислил индекс? А вдруг в списке всего один элемент? Правда, и tcl не выдаст ошибки, а выдаст пустую строку, но зато хотя бы есть способ _ясно_ сказать, что я имею в виду именно элемент энный с конца. Это вроде мелочь, но в tcl таких мелочей много и они хорошо складываются.

Соответственно, вопрос такой: откуда такие красивые мелочи в tcl, и где ещё подобное есть?

И вот предварительные итоги опроса

( читать дальше... )

 , ,

den73
()

улучшение поддержки named-readtables в SLIME

Форум — Development

Похоже, есть определённые движения в направлении добавления более качественной поддержки named-readtables в SLIME. На данный момент поддержка оформлена в виде довольно неэлегантного костыля, и вроде бы родилось решение, как начать переход к более правильному варианту без нарушения работы ныне здравствующего кода. Прошу происоединяться к дискуссии на SLIME-devel.

 , ,

den73
()

tk: Сделать мозаику из окон

Форум — Development

Хочу сделать автоматический layout своих нескольких toplevel окон, чтобы они разлеглись мозаикой. Если монитора более одного, то они должны разлечься на одном из мониторов.

Причём мозаика может быть неравного размера. Допустим, редактор занимает 3/4 экрана, а остальные окошки к нему сбоку прилеплены (как это обычно бывает в IDE)

 , ,

den73
()

это баг в SBCL или я что-то не понял?

Форум — Development
(declaim (optimize (speed 3) (safety 0) (compilation-speed 0) (space 0) (debug 0)))

(declaim (ftype (function (fixnum ) fixnum) FOO ))

(defun FOO  (X  )
 (declare (type FIXNUM  X ))
  (+ X 1)
  )

(declaim (ftype (function (NUMBER ) NUMBER) BAR ))

(defun BAR (X)
  (declare (type NUMBER X))
  (FOO X)
  )

Этот код компилируется без предупреждений. Если заменить number на string, то будет warning. Чтение мануала не помогло. Другие значения safety (до 3) не помогли.

 

den73
()

Макросы в Scala против макросов в Common Lisp

Форум — Development

Я почитал туториал от 2016 года и написал очень краткую выжимку из него.

Что можно сказать? Во-первых, CL как язык для МП устаревает и теряет привлекательность буквально у нас на глазах. В scala, конечно, МП менее удобно из-за более сложного синтаксиса, зато в Scala появилась концепция семантической БД - это результат семантического анализа текста со всеми типами данных и декларациями. В CL такой семантической БД нет. Притом что Scala - это даже не первый такой язык. Если я правильно понял, clang тоже такое умеет.

Среди не афишируемых целей проекта Яр есть цель сделать именно такую семантическую БД. Теперь нет смысла это скрывать.

Поимимо этого, кто не в курсе - Common Lisp _не является_ гомоиконным языком, потому что есть #. , квазицитаты частично обрабатываются, а комментарии теряются. Другие побочные эффекты чтения - это создание символов в пакетах. macro character-ы назначенные пользователем, могут делать что угодно, вплоть до запуска ракеты. Т.е. нельзя зачитать файл лиспа и проанализировать его средством без последствий для среды. Вообще нельзя. Для Java и C это сделать можно, а для лиспа - нет. Фига себе, да? Ещё одной целью проекта Яр является создание истинно гомоиконного языка. Причём это не моя прихоть, а обязательное условие для создания полноценной IDE, а не набора костылей, каковым является SLIME.

Если ещё остались энтузиасты лиспа, можно попробовать сделать семантическую БД для CL. Есть augment-environment, к-рая поддерживается в CCL. В ней есть кое-какая информация о типах. Хотя на самом деле скорее всего придётся патчить компиляторы.

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

И ещё одно странное наблюдение - похоже, что макросы в Scala никому особо не нужны.

 , ,

den73
()

Яр - как правильно спроектировать структуру данных строковых типов

Форум — Development

Ответ на Яр - какие ф-ии работы со строками включить в стандартную библиотеку? (комментарий)

http://www.sbcl.org/manual/#Unicode-Support - похоже, что в SBCL строки не содержат в себе локали (хотя они являются массивами букв и в этом твоё пожелание выполненио).

В лиспворксе тоже что-то не видно той архитектуры, к-рую ты хочешь. Есть внешние форматы, а про collation ничего нет

Т.е. ты хочешь сказать, что надо глянуть и в формат SQL, где это прописано. Привожу цитату из доки любимого сервера всех пользователей Linux, т.е.из Ms SQL.

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

Параметры сортировки уровня базы данных При создании или изменении базы данных можно задать параметры ее сортировки по умолчанию с помощью предложения COLLATE в инструкции CREATE DATABASE или ALTER DATABASE...

Параметры сортировки уровня столбцов... - это и есть то, что надо.

Параметры сортировки уровня выражений...

SELECT name FROM customer ORDER BY name COLLATE Latin1_General_CS_AI;  

В лиспворксе есть external-formats и есть сравнение строк для юникода, но к строке они опять же не прилеплены.

Проблема с ё представляется мне важной. Раз юникод кривой, мы будем от него абстрагироваться.

Если вы знаете иной ЯП, где задача приклейки локали к строкам решена, то дайте знать.

Я сразу могу сказать про такие грабли: «Смесь french с нижегородским» - как сравнивать такую строку и как привести её к верхнему регистру? Очевидно, строка многоязычна и у неё не может быть такого атрибута, как локаль. Если локаль приклеена к букве, то это уже легче.

Пока у меня ничего не вырисовывается, разве только вот такое:

Письменность - система, охватывающая все вопросы представления
строк в компьютере: кодировка строк в виде массивов, сравнение,
приведение регистра, определение языка, изображение на экране.
Как минимум, есть три письменности: юникод, koi-8r, GB_18030
(если я правильно понял смысл последнего). 

Литера - абстрактная структура метаданных. Её атрибуты
  Письменность
  Номер (необязательно)
  Абстрактный глиф
  Понятное людям описание
  Языки, в к-рых может присутствовать
   
Кодировка - способ превращения литер или строк из литер в
массивы цифр и обратн в рамках одной письменности

Внешний формат - способ преобразования письменностей и/или кодировок.

В этой структуре пока не определен тип данных «строка» и не решён вопрос про «смесь french с нижегородским». Вопрос: правильно или нет?

 ,

den73
()

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