LINUX.ORG.RU

Почему считается, что CL подходит только для мегасложных проектов?

 


1

5

Я так понимаю это суждение относится к особенностям реализации а не к языку. Но есть же clisp, поддерживающий CFFI и имеющий свой FFI, который может перенять стратегию паразитизма python на C. Вполне годен для написания мелкой скриптоты, а там и до медиаплееров, жаббер-клиентов рукой подать. А через некоторое время стабилизируется поддержка многопоточности...

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

ifstream( fname, ios::binary ).read( buf, m * n * 4 );

(with-open-file (f fname :element-type '(unsigned-byte 32)) (read-sequence buf f))

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

Это не сериализация, а десериализация (чтение).

serialization is the process of converting a data structure or object state into a format that can be stored (for example, in a file or memory buffer, or transmitted across a network connection link) and «resurrected» later in the same or another computer environment.

википедия, как обычно. Одно без другого (часто) бессмысленно, а писать сериализация/десериализация слишком долго. Код сериализации тоже нужно бы привести, потому что он неправильный.

Давай ты объяснишь, что _точно_ делает этот код. Думаю, будет смешно.

Написать что делает каждая строчка? Думаю, понятно где определения типов, где функций, где макросов и где декларации типов переменных. Несколько замечаний. deftype это типа typedef, с той разницей, что в определении типа можно использовать типы интервалов (например, тип числа больше 10, но меньше 100), составлять типы из уже имеющихся типов с помощью or, and и not, иметь параметры у типов и макро-образно генерировать определение типа из произвольных параметров типа. Отсутствие статической системы типов снимает всякие вопросы о консистентности таких типов. swap-u32-bytes меняет endianes (это, наверно, нехорошо, лучше что-то вроде htonl/ntohl). Ещё в CL есть (настоящие) массивы в стандарте, with-array-data это такая штука которая абстрагирует такой код:

(let* ((a (make-array '(2 2) :initial-contents '((1 2) (3 4))))
       (b (make-array 4 :displaced-to a)))
  (format t "~S~%" (aref a 1 1))
  (format t "~S~%" (aref b 3)))
4
4
NIL

то есть 2-мерный массив можно использовать как 1-мерный, a и b это одна область памяти индексация к которой проводится как 2-мерному массиву в случае a и как к 1-мерному массиву в случае b. В Си можно взять u32** и сериализировать записью количества строк, столбцов и потом write в цикле для каждой строки, либо взять u32*, написать u32 get(u32*, index, index), void set(u32*, u32, index, index) и сериализировать одним write, ещё в C99 можно упаковать u32* в variable sized structure, в конце концов, можно навелосипедить нормальных массивов с гибкой индексацией.

with-open-file гарантированно закрывает открытый файл (макрос абстрагирует unwind-protect, это типа локальных исключений без выбора по типам исключений):

(with-open-file (in filename :element-type 'u32)
  (read-sequence contents in))

это, собственно, всё чтение.

Смешно может быть то, что 2-мерный массив записывается как 1-мерный без сериализации размеров матрицы, так что придётся звонить «Васе» и спрашивать - «какие m и n подставить для файла который ты мне прислал?» :)

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

ifstream( fname, ios::binary ).read( buf, m * n * 4 );

Эм, read(2)? void* != matrix_u32 потому что интерфейсы типов void* и matrix_u32 совсем не совпадают - что с этим void* дальше делать, как его, например, транспонировать? Для аналога нужно, как минимум, писать файловый RAII и шаблонные классы массивов с параметризацией по типам элементов и возможностью плоской и матричной индексации. Потом уже методы сериализации.

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

void* != matrix_u32 потому что интерфейсы типов void* и matrix_u32 совсем не совпадают - что с этим void* дальше делать, как его, например, транспонировать? Для аналога нужно, как минимум, писать файловый RAII и шаблонные классы массивов с параметризацией по типам элементов и возможностью плоской и матричной индексации. Потом уже методы сериализации.

#include <fstream>
#include <stdint.h>
#include <vector>
using namespace std;

template<typename T>
struct Matrix
{
	vector<T> buf_;
	size_t m_, n_;

	Matrix( size_t m, size_t n ) : buf_( m * n ), m_( m ), n_( n ) {}
	void load( const char* fname ) { ifstream( fname, ios::binary ).read( (char*) &buf_.front(), m_ * n_ * sizeof(T) ); }
	void save( const char* fname ) { ofstream( fname, ios::binary ).write( (char*) &buf_.front(), m_ * n_ * sizeof(T) ); }
	T* operator[]( int index ) { return &buf_.front() + index * n_; }
};

int main()
{
	Matrix<uint32_t> m( 10, 10 );
	m[5][5] = 12345;
	m.save( "1.dat" );
	
	m.load( "1.dat" );
	printf( "%d\n", m[5][5] );
}

внезапно, тот самый:

ifstream( fname, ios::binary ).read( (char*) &buf_.front(), m_ * n_ * sizeof(T) );
vaino
()
Ответ на: комментарий от quasimoto

Смешно может быть то, что 2-мерный массив записывается как 1-мерный без сериализации размеров матрицы, так что придётся звонить «Васе» и спрашивать - «какие m и n подставить для файла который ты мне прислал?» :)

Размеры могут быть в другом месте - в имени файла например, или быть известны априори. Это зависит от задачи.

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

Это не сериализация, а десериализация (чтение).

serialization is the process of converting a data structure or object state into a format that can be stored
википедия, как обычно.

И? Насколько я понимаю, код на Лиспе выполняет как раз противоположное действие: «The opposite operation, extracting a data structure from a series of bytes, is deserialization». Где я неправ?

Написать что делает каждая строчка?

Нет. Написать, что делают они все вместе. Например: «этот код читает из файла 1-мерный массив чисел с плавающей точкой, при необходимости преобразует endianness, и вохзвращает объект XXX, обладающий свойствами YYY». Потому что код выглядит непонятно зачем навороченной версией:

{
int i;
int fd = open(fname, O_RDONLY);
float m = calloc(n, sizeof(float));

read(fd, m, n*sizeof(float);
for (i = 0; i < n; i++)
  swap32(m[i]);
return m;
}

(только не надо рассказывать про необходимость RAII - мне сейчас тупо лень писать код чистки ресурсов).

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

Мы пишем операционные системы, которые работают везде — от смарт-карт, мобильников, DVD-проигрывателей до мощнейших кластеров, АЭС и космических аппаратов.

Это шизофрения+мания величия у одного человека, или это новое сообщество анонимус девелоперс прорезалось?

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

Вы ПЫТАЕТЕСЬ запускать исследовательские аппараты в глубины космоса но ПОЛУЧАЕТСЯ только в подводные пучины. Ну, если Вы и правда для них софт пишете, то теперь понятно почему так...

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

Вроде того. Только полезных функций больше - их бы в абстрактные интерфейсы вынести (Serializable, Printable (преобразование в строку, печать в поток), Readable (разбор из строки, чтение из потока), Array (ранг, количество элементов) и т.п.), массивы это не только матрицы, допустима любая другая размерность (нужно n-ое количество шаблонных классов - Vector = Array1, Matrix = Array2, Array3, ...) и необходима возможность индексировать m-мерные массивы как n-мерные (m и n - любые). С отсутствием в языке синтаксических списков ('((1 2 3) (4 5 6))) и массивов (#2A((1 2 3) (4 5 6))) ничего не сделать.

Вот такой код будет работать для массивов любой размерности:

(defun read-array (path dimensions &key (element-type '(unsigned-byte 32)))
  (let* ((array (make-array dimensions :element-type element-type))
         (buffer (make-array (array-total-size array) :element-type element-type :displaced-to array)))
    (with-open-file (in path :element-type element-type)
      (read-sequence buffer in)
      array)))

(defun write-array (path array)
  (let ((buffer (make-array (array-total-size array) :element-type (array-element-type array) :displaced-to array)))
    (with-open-file (out path :direction :output :element-type (array-element-type array))
      (write-sequence buffer out)))
  (values))

типы можно не декларировать (SBCL, например, их выведет).

Кстати:

(defmethod serialize ((array (array * (* *))) path)
  (values))

;; ARRAY fell through ECASE expression.
;; Wanted one of (SB-PCL::CLASS-EQ EQL).

(defclass matrix (array) ())

;; The class #<BUILT-IN-CLASS ARRAY> was specified as a super-class
;; of the class #<STANDARD-CLASS MATRIX>, but the meta-classes
;; #<STANDARD-CLASS BUILT-IN-CLASS> and
;; #<STANDARD-CLASS STANDARD-CLASS> are incompatible.  Define a
;; method for SB-MOP:VALIDATE-SUPERCLASS to avoid this error.

(defstruct matrix ?
  (array nil :type (array ? (* *))))

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

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

наверное float* m?;-)

И зачем swap32 (я только догадываюсь че оно делает), откуда известино что порядок надо менять?

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

наверное float* m?;-)

Конечно.

И зачем swap32

В коде на Лиспе есть такая функция (с семантикой ntohl для x86. насколько я понял).

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

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

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

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

Это да, если на лиспе был действительно эквивалентный пример... то я понимаю почему на нем не пишутЪ;-)

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

Написать, что делают они все вместе.

К примеру, код постом выше - чтение/запись содержания массива произвольного ранга в файл (та версия делает то же самое). Т.е. многомерные массивы - часть языка:

(type-of #2A((1 0) (0 1))) ;; 2x2 matrix
(SIMPLE-ARRAY T (2 2))

с массивом произвольной размерности (в том случае - матрица) можно работать как с массивом какой-то другой размерности, например, как с простым одномерным массивом который всегда можно прочитать/записать из/в файл c помощью read-sequence/write-sequence. Ну и with-open-file это такой файловый RAII.

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

с массивом произвольной размерности (в том случае - матрица) можно работать как с массивом какой-то другой размерности,

Вообще то такая фишка тривиально организуется на любом ЯП. На C/C++ так это вообще из коробки.

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

На C/C++ так это вообще из коробки.

Это как? arr[i / m][i % m] или arr[i * m + k]? В си вообще нет массивов большей размерности чем 1.

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

Читает матрицу MxN, конвертируя BE при необходимости. Все что выше последней функции - обертка «оптимизации» для SBCL

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

В си вообще нет массивов большей размерности чем 1.

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

#include <fstream>
#include <stdint.h>
using namespace std;

template<typename T, int m, int n>
struct Matrix
{
	T buf_[m][n];

	void load( const char* fname ) { ifstream( fname, ios::binary ).read( (char*) &buf_[0][0], m * n * sizeof(T) ); }
	void save( const char* fname ) { ofstream( fname, ios::binary ).write( (char*) &buf_[0][0], m * n * sizeof(T) ); }
	T* operator[]( int index ) { return &buf_[index][0]; }
};

int main()
{
	Matrix<uint32_t,10,10> m;
	m[5][5] = 12345;
	m.save( "1.dat" );
	
	m.load( "1.dat" );
	printf( "%d\n", m[5][5] );
}
vaino
()
Ответ на: комментарий от vasily_pupkin

Читает матрицу MxN, конвертируя BE при необходимости. Все что выше последней функции - обертка «оптимизации» для SBCL

Хм. Полагаю, что «просто чтение с конвертированием» - это вставка функции конвертации в примерно такой код:

(with-open-file (f fname :element-type '(unsigned-byte 32)) (read-sequence buf f))

А «обертки оптимизации» делают из короткого и даже красивого Лисп-кода кашу похуже Си.

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

Это такой стиль написания, например - такой наворот

Мое Лисп-фу примерно на нуле, но, видя define-instruction и setf emitter, я начинаю подозревать расширение компилятора. Ну и причем тут функция десериализации матрицы?

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

((C != C++ ) == false)==true но ты знай

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

int a[10][10];

ничего страшного

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

А «обертки оптимизации» делают из короткого и даже красивого Лисп-кода кашу похуже Си.

В кои то веки согласен. А за переопределение типа для кода в 10 строк вообще удавить охота :) Создаётся впечатление, что многим (даже хорошим) лисперам принцип KISS не то что незнаком, а просто противен. Так и норовят написать «собственный диалект», а уже на нём - всё остальное.

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

ну и?

это ты должен сказать, что ты подразумевал под C != C++ и «В си вообще нет массивов большей размерности чем 1», формально - да, это массив массивов, но по факту - разницы нет

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

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

Если верить ЛОР, именно такой стиль является Ъ-Лиспом :)

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

суть : выкати код с многомерным массивом на С и это твой win над квазимодо :)

суть для С и С++ различна С++ на этапе компиляции делает многое то что в С делается либо в рантайме(куча чеков если охота классами) либо злоупотреблением препроцессора

твой пример не пример :)

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

самая базовая придирка

так как по using ты юзаеш С++ значит утя возможно перегружено обращение по индексу и как следствие уже в этом месте твой сырец не есть доказательство для С ибо в С как тебе(я надеюсь) известно нет перегрузки «операций»

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

Есть

http://c-faq.com/aryptr/pass2dary.html, частично - T[][] нельзя вернуть из функции, T[][] суть T(*)[], T[][] нельзя передать аргументом, можно передать T[][n], т.е. T(*)[n], T[][], T*[] и T*[n] нельзя инициализировать, можно инициализировать T[][m]. Это не настоящие массивы, всё ещё плоская память с плюшками.

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

суть : выкати код с многомерным массивом на С

#include <stdio.h>
#include <stdint.h>

void load_matrix( const char* fname, void* p, size_t size )
{
	FILE* f = fopen( fname, "rb" );
	fread( p, size, 1, f );
	fclose( f );
}

void save_matrix( const char* fname, void* p, size_t size )
{
	FILE* f = fopen( fname, "wb" );
	fwrite( p, size, 1, f );
	fclose( f );
}

int main()
{
	// u32

	uint32_t m1[10][10];
	m1[5][5] = 12345;
	save_matrix( "1.dat", m1, sizeof m1 );

	m1[5][5] = 0;
	load_matrix( "1.dat", m1, sizeof m1 );
	printf( "%d\n", m1[5][5] );

	// u64

	uint64_t m2[10][10];
	m2[5][5] = 12345;
	save_matrix( "2.dat", m2, sizeof m2 );
	
	m2[5][5] = 0;
	load_matrix( "2.dat", m2, sizeof m2 );
	printf( "%d\n", m2[5][5] );
}

можно было бы добавить один макрос для краткости, но не добавил - т.к. тебе они вроде не нравятся

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

Молодец . теперь удостоверься что квазимодо ознакомлен с твоим С сырцом

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

Ну и причем тут функция десериализации матрицы?

Я про стиль - shebang casы на каждую реализацию, декларации типов на каждую функцию и let-подобную конструкцию, многочисленные deftype, многочисленные микро-макросы (типа with-array-data), ну и более мощные макросы реализующие какой-то eDSL (типа define-instruction). Получаются такие портянки. В исходном примере декларации типов для массивов не нужны, вся информация уже есть в make-array и в объектах array, так что реализация сама может (должна) сделать себе эти декларации (SBCL так делает). Так что, вычёркиваем deftype и пару declare. Эффект от типизации swap-u32-bytes может быть, от типизации read-u32-matrix - вряд ли, вычёркиваем ещё один declare. Макрос with-array-data просто делает одну строчку короче, может иметь смысл если повсюду displaced массивы и их лень явно расписывать (sb-kernel:with-array-data - написан), для иллюстрирующего примера этот макрос тоже можно удалить. Итого, остаётся swap-u32-bytes (с inline и declare) и read-u32-matrix (без declare).

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

void *

нет смысла передавать что-то другое для fread/fwrite

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

Это как? arr[i / m][i % m] или arr[i * m + k]? В си вообще нет массивов большей размерности чем 1.

Т.е. C Вы не знаете... слив засчитан.

double arr[10][10];

for( int i=0; i<10; i++)
   for( int j=0; j<10; j++) 
       arr[i][j] = ...;

for( int i=0; i<100; i++) ((double*)arr)[i] = ...;
AIv ★★★★★
()
Ответ на: комментарий от tailgunner

То есть ты хочешь сказать, что половина кода рассматриваемого примера - лишняя?

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

В остальном - вопрос стиля. Язык вообще динамический и не требует деклараций типов, будут ли эти декларации иметь эффект зависит от реализации (стандарт ничего не требует, так как бывают интерпретаторы CL). Тем не менее, если их использовать, то есть выбор - писать везде (unsigned-byte 32) или определить тип u32. Ну как в си - можно наделать коротких typedef-ов для числовых типов, писать typedef struct - может быть удобно, может быть порицаемо. Также, если есть массив x, то чтобы завести плоский displaced массив нужно сделать

(let ((y (make-array (array-total-size x) :element-type (array-element-type x) :displaced-to x)))
  ;; ...
  )

если хочется писать короче

(with-data-array (y x)
  ;; ...
  )

то нужно написать

(defmacro with-data-array (data-array array &body body)
  `(let ((,data-array (make-array (array-total-size ,array) :element-type (array-element-type ,array) :displaced-to ,array)))
    ,@body))

опять же вопрос - надо это или нет.

Вот в питоне нет деклараций типов и статической системы типов (?), макросов, макросов чтения, так что подобных стилевых вопросов не возникает.

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

Вот в питоне нет деклараций типов и статической системы типов (?), макросов, макросов чтения, так что подобных стилевых вопросов не возникает.

В питоне они просто не нужны;-)

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

Вот в питоне нет деклараций типов и статической системы типов (?), макросов, макросов чтения, так что подобных стилевых вопросов не возникает.

В питоне они просто не нужны;-)

Убил бы ради статически типизированного Питона %)

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

Хочу напомнить, что quasimoto утверждал:

1) CL умеет работать с массивами произвольной размерности, и предоставлять альтернативный доступ к таким массивам. Я говорю что это можно делать почти в любом ЯП. Вот для питона пример:

arr = {}
for i in range(10) :
   for j in range(10) :
       arr[i,j] = ...

for k, v in arr.items() : ...

2) «в С нет многомерных массивов» - это просто 4.2. Неважно, каким образом там эти многомерные массивы реализуются - для пользователя результат не отличается от Ъ многомерных массивов. И неважно, какие хитренькие принципы используются при реализации альтерантивного доступа - это в С стандартный прием, и кстати расположение данных в памяти для такого случая ЕМНИП прописано в стандарте, это не хак.

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

Убил бы ради статически типизированного Питона %)

Это будет уже окамл?

ИМНО просто можно тестить типы аргументов ф-ии при вызове, у меня даже есть декоратор для этого. Ну или написать тулзу, к-я анализирует питонячий код;-)

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

Убил бы ради статически типизированного Питона %)

Это будет уже окамл?

Эх... нет, Окамл из Питона всё равно не получится.

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

Смысл - в статической проверке.

Ну или написать тулзу, к-я анализирует питонячий код;-)

Что-то никто не пишет :/

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