LINUX.ORG.RU

Реализация рестартов из Common Lisp в C++

 ,


1

3

https://github.com/BerserkerTroll/restart-pp

Пример использования:


#include "restartable.h"
#include <iostream>
#include <cmath>
using namespace std;


struct bad_my_sqrt_parameter { double param; }; // condition

struct my_sqrt_use_value { double val; }; // restart
struct my_sqrt_recalculate { double val; }; // restart


double my_sqrt(double d)
{
	if (d < 0)
		restartable {
			signal_condition bad_my_sqrt_parameter{ d };
		} restart_case (my_sqrt_use_value& v) {
			return v.val;
		} restart_case (my_sqrt_recalculate& v) {
			return my_sqrt(v.val);
		};

	return sqrt(d);
}


int main()
{
	with_handlers {
		cout << my_sqrt(+4) << endl;
		cout << my_sqrt(-4) << endl;
	} handler_bind (bad_my_sqrt_parameter&) {
		invoke_restart my_sqrt_use_value{ -1 };
	};

	with_handlers {
		cout << my_sqrt(+4) << endl;
		cout << my_sqrt(-4) << endl;
	} handler_bind (bad_my_sqrt_parameter& p) {
		invoke_restart my_sqrt_recalculate { -p.param };
	};
}

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

Много ли требуется решать задач, где где функция должна отработать не больше чем, скажем, за 0.003 секунды

Есть очень много задач, где время работы составляет около 10-20 минут. А на CL она же отрабатывает уже за час с лишним.

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

Есть очень много задач, где время работы составляет около 10-20 минут. А на CL она же отрабатывает уже за час с лишним.

Тот болтёнок, который тормозит всю программу, можно переписать на C или C++ :-) Или прям каждая конструкция у тебя тормозит? :-)

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

tmp = dlopen(«tmp.so»);

Во-первых, dlclose() работает не везде :-) В том же любимом тобою Racket и то нельзя либу перезагрузить без перезагрузки всего процесса - один раз открыл и радуйся :-) А в разработке надо DrRacket перезагружать, очень удобно, да :-) Лол :-)

obj->fun = dlsym(tmp, «generated»);

Во-вторых, ты что, будешь в vtbl руками лазить? :-) А в-третьих, обычные функции уже не заменишь, они не first class citizens :-) Так что это всё на фоне Лиспа тускло :-)

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

Или прям каждая конструкция у тебя тормозит?

А вот это уже фиг выяснишь. Вот есть, например, http://benchmarksgame.alioth.debian.org/u64q/program.php?test=regexdna&la... . Работает 20.8 секунды там, где вариант на C++ работает 3.9 секунды. Какой кусок переписать на C++ ?

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

Для чистой скриптухи удобнее ruby. Но он тормозной жутко.

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

В том же любимом тобою Racket и то нельзя либу перезагрузить без перезагрузки всего процесса - один раз открыл и радуйся

Можно. dynamic-rerequire есть.

А в разработке надо DrRacket перезагружать

Зачем? Сохраняешь библиотеку. Нажимаешь выполнить, она пересобирается и загружается. Мне DrRacket приходилось перезагружать только когда потоки из программы запускал и они ошибочно не завершались и продолжали работать. Тогда перезагрузка модуля не убивала потоки.

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

Какой кусок переписать на C++ ?

Профайлер, не? :-)

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

Числодробильня, понятное дело, на C быстрее :-)

Для чистой скриптухи удобнее ruby. Но он тормозной жутко.

А Racket, не? :-)

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

V8 или luajit не пробовал?

Они медленней, чем SBCL и менее удобные, чем Common Lisp или Racket.

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

Можно. dynamic-rerequire есть.
Зачем? Сохраняешь библиотеку. Нажимаешь выполнить, она пересобирается и загружается.

Ты про что? :-) Я про FFI и внешние либы:

Due to the way the operating system performs dynamic binding, loaded libraries are associated with Racket (or DrRacket) for the duration of the process. Re-evaluating ffi-lib (or hitting the Run button in DrRacket) will not force a re-load of the corresponding library.

http://docs.racket-lang.org/foreign/Loading_Foreign_Libraries.html

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

Профайлер, не? :-)

Попробуй. Там как-бы «каждая конструкция тормозит».

Числодробильня, понятное дело, на C быстрее :-)

Так почти всё быстрее. Если не считать скрипты, когда вся суть программы дёрнуть библиотеку на Fortran/C или СУБД и подождать результата.

А Racket, не? :-)

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

Ruby — идеальный скриптовый язык. Лаконичный как perl, гибкий как CL (monkey patching во все поля), наличие всех нужных возможностей (слабые ссылки, финализаторы, проодолжения).

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

Я про FFI и внешние либы:

Тогда я не понял, зачем её перезагружать. Она же не меняется в процессе.

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

Racket — это правильный CL.

Ну если это так, тогда не правильно соотносить Common Lisp <-> Racket и C <-> C++, потому что C++ - не правильный C :-)

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

Тогда я не понял, зачем её перезагружать. Она же не меняется в процессе.

Ну ты же собрался вызывать dlopen() :-) 1 раз ты откроешь либу :-) После того, как ты её перекомпилируешь, Racket/DrRacket надо будет перезагружать, чтобы он подгрузил новую версию :-) Это потому, что перезагрузка либ на лету работает не везде :-) Так что в работающем цепепе компилить/перезагружать код на горячую, даже в примитивном виде аля dlopen/dlclose можно не везде :-)

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

тогда не правильно соотносить Common Lisp <-> Racket и C <-> C++, потому что C++ - не правильный C

С этой точки зрения — да.

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

Так что в работающем цепепе компилить/перезагружать код на горячую, даже в примитивном виде аля dlopen/dlclose можно не везде

Сборки мусора всё равно нет. Можно просто плодить по временному файлу на каждую компиляцию. Ещё можно вместо dlopen просто читать машкод в переменную, и затем преобразовывать тип и выполнять. Я просто навскидку не помню, как заставить g++ чистый машкод сделать или как выдрать его из бинарника. В общем, было бы желание, решение существует.

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

Проще clang-ом jit-ить, чем с временными файлами и dlopen возиться.

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

обсуждаются реальные задачи

лисподаун притащил очередной бенчмарк факториала

Лисподауны нева чендж.

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

http://benchmarksgame.alioth.debian.org/u32/performance.php?test=mandelbrot

Прикольно. Подтверждаю, на моём компьютере сишная версия работает 44 секунды, а лисповая — 29. gcc 6.1.1 x64.

Что доказывает, что лисперы не умеют в С, вот вам нормальные версии:

http://benchmarksgame.alioth.debian.org/u32/performance.php?test=mandelbrot

anonymous
()
Ответ на: http://benchmarksgame.alioth.debian.org/u32/performance.php?test=mandelbrot от anonymous

вот вам нормальные версии:

Ну да. Набрать памяти на всю картинку — очень эффективный алгоритм. И в https://gist.github.com/monoid/1770691 MSTEPS = 50000, а в http://benchmarksgame.alioth.debian.org/u32/performance.php?test=mandelbrot MAXIMUM_ITERATIONS = 50.

Поменял на MAXIMUM_ITERATIONS на 50000:

$ gcc -O3 test.c
$ time ./a.out 1024 > test2.pgm

real	1m21.389s
user	1m21.272s
sys	0m0.004s

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

Набрать памяти на всю картинку — очень эффективный алгоритм.
Поменял на MAXIMUM_ITERATIONS на 50000
real 1m21.389s

Лол :-)

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

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

Hertz ★★★★★
()
Последнее исправление: Hertz (всего исправлений: 1)
Ответ на: комментарий от Hertz

На основе какой ревизии Схемы базируется нынешний Racket?

Сложно сказать. Наверное, ближе всего будет r6. Но, фактически, Racket не является никакой ревизией схемы: в Racket иммутабельные списки, символы регистрозависимые, количество своих расширений огромно, причём начиная с базового синтаксиса: (1 . < . 2), (λ (x) x), нет библиотек, вместо них модули.

С другое стороны, в Racket в стандартных языках полностью поддерживается r5rs и r6rs. И есть независимый язык r7rs.

monk ★★★★★
()
Ответ на: C-версия быстрее от utf8nowhere

Объясни, о многомудрый, как ты смог получить результат противоречащий результатам людей, которые (я точно знаю) очень хорошо разбираются в Си и крестах?

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

очень хорошо разбираются в Си и крестах

Значит не очень хорошо разбираются, если не заметили, что gcc поставлен в неравное положение по сравнению с лиспом. Если поставить их в равное положение, то лисп ожидаемо отсасывает.

Поймите же, ну не может нетипизированное интерпретируемое скобочное говно быть быстрее няшной сишки! Если вам показалось, что таки быстрее, то, очевидно, что скобкодауны вас где-то [обманули]. Стоит устранить обман и картина реальности вновь становится непротиворечивой.

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

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

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

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

ПОКАЖИ КОД!

Хочу познать способ ускорения сишки вдвое, путём чтения мануала sbcl.

anonymous
()
Ответ на: C-версия быстрее от utf8nowhere
$ time ./lsp

real	0m11.100s
user	0m11.072s
sys	0m0.007s
$ time ./c 

real	0m43.590s
user	0m43.680s
sys	0m0.012s

Хороший редактор Emacs :-) На Лиспе написан :-) Лол :-)

anonymous
()
3 ноября 2016 г.

Переписал чутка код.

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