LINUX.ORG.RU

[common lisp] создание fasl-ов в реалтайме?

 


0

0

нужно по ходу работы программы сохранять в файл(в любом формате пригодном для дальнейшего возрождения в программу) лямбды. Сначала сделал по привычке через cl-store, но оказалось что он не умеет правильно работать с ф-циями. С другой стороны на ум сразу приходит идея компилить и делать в будущем просто load. Я так, видимо, и сделаю. Только прийдётся сохранять все такие ф-ции с одним именем, в текстовом формате(это ужасно! мне придётся изменить внутреннее представление этих ф-ций). Как-то некрасиво получается, ведь всё что мне нужно - работать с объектами-функциями как с объектами, а не как с областями определений. Может есть какой-то способ?

Как-то невнятно пишу, вот так понятнее наверн будет) -

;вот как было бы всё просто при рабочем cl-store:
(cl-store:store (lambda () 1) "test") ;  save
(funcall (cl-store:restore "test"))
1

;а вот так пока видится это сейчас:
(save-as-text "(defun sled () (lambda () 1))" "test")
(compile-file "test")
(load "test.fasl")
(funcall (sled))
1

;так-то даже ничего, но хз что будет при попытке распараллеливания, к примеру

★★★

Последнее исправление: pseudo-cat (всего исправлений: 1)

рабочий быдлокод:

(defvar *func-hash* (make-hash-table :test #'equalp))

(defmacro defsfun (name args &body body)
  `(progn
     (defun ,name ,args
       ,@body)

     (setf (gethash ',name *func-hash*)
           `(defun ,',name ,',args
             ,',@body))))

(defun serialize (stream func-name)
  (print (gethash func-name *func-hash*) stream))

(defun deserialize (stream)
  (let ((form (read stream)))
    (let ((func-name (cadr form)))
      (compile func-name))))

(defsfun add (a b)
  (+ a b))

(let ((dump
       (with-output-to-string (out)
         (serialize out 'add))))
  (with-input-from-string (in dump)
    (deserialize in)))
anonymous
()
Ответ на: комментарий от anonymous

ахах, а я то наивный -

CL-USER> (defclass cool ()
	   ((fun :initarg :fun :accessor fun)))
#<STANDARD-CLASS COOL>
CL-USER> (cl-store:store (make-instance 'cool :fun (lambda () "yeah?"))
			 "/home/lindie/tmp/testtt")
#<COOL {B410661}>
CL-USER> (defparameter *obj* (cl-store:restore "/home/lindie/tmp/testtt")) 
; Evaluation aborted.

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

pseudo-cat ★★★
() автор топика
Ответ на: комментарий от anonymous

А, речь про лямбды. ;-) Ну идея понятна.

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

[code=lisp] (defun deserialize (stream) (let ((form (read stream))) (compile (eval form)))) [/code]

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

>http://www.lisper.ru

Так же все лисперы, бессмысленно.

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

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

> ты дебил или просто тролль?

Судя по его комментариям - первое.

anonymous
()

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

Попробуйте также воспользоваться sb-heapdump.

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

остаётся главная проблема - нужны идентификаторы для хранения в кода в базе. Хочется как-то без них. Ввести новое предстовление? аля (<function> source-code)? затратно. Хотя в будущем, потенциально, может пригодиться исходный код ф-ции - можно использовать его только для сохранения и дальнейшей компиляции, а в потом просто брать(из файлов .lisp и .fasl) то представление, которое нужно; и работать вполне сносно(в случае когда нужен fasl) с замыканием.

cl-store+... у меня отказалось компилиться(нет компоненты METATILITIES). Да и не хочется его как дополнительную зависимость таскать, если можно сделать как вы предложили

pseudo-cat ★★★
() автор топика
Ответ на: комментарий от pseudo-cat

в кода в базе

без в)

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

pseudo-cat ★★★
() автор топика
Ответ на: комментарий от pseudo-cat

короче пока написал такой костыль, ну как обычно временный) зато простой)

если в дальнейшем прийдётся распараллеливать прогу - добавлю мьютекс в deserialize

(in-package :cl)

(defpackage #:serial
  (:use :cl)
  (:export "serialize"
	   "deserialize"))

(in-package :serial)

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;; serialize 

(defparameter *sled-to-lambda* nil)

(defun serialize (pth-name source)
  (with-open-file (out pth-name :direction :output :if-exists :supersede
		       :if-does-not-exist :create)
    (format out "(defparameter *sled-to-lambda*")
    (print source out)
    (format out ")"))
  (compile-file pth-name))

(defun deserialize (pth-fasl)
  (load pth-fasl)
  (let ((obj-fun *sled-to-lambda*))
    obj-fun))

а вообще непойму, почему в cl-store просто не добавят сериализацию для всех(пригодный) объектов. Уже использую эту библиотеку в том коде, куда вставляю выше приведённый костыль и было бы классно обойтись без него

pseudo-cat ★★★
() автор топика
Ответ на: комментарий от pseudo-cat

>а вообще непойму, почему в cl-store просто не добавят сериализацию для всех(пригодный) объектов

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

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

dmitry_vk ★★★
()
Ответ на: комментарий от pseudo-cat

(format out "(defparameter *sled-to-lambda*")

Так делать (писать в вывод лисп-код из стрки) не очень хорошо, лучше ИМХО сделать примерно так:

(print `(defparamter *sled-to-lambda* ,source))
Т. е. мы сначала строим требуемый код в виде списков, а потом его выводим. За счёт этого мы сохраняем код, который по крайней мере считываться будет без ошибок. Плюс при таком подходе можно всякие более хитрые преобразования над кодом выполнять.

а вообще непойму, почему в cl-store просто не добавят сериализацию для всех(пригодный) объектов

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

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

выглядит более опрятно, спасибо. Меня на такую(с format) запись подтолкнуло, что format съедал кавычки в теле ф-ции

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

в смысле если сначала проверять сохраняемый код eval-ом? Да, кстати, это наверное нужно будет, чтобы проверять до сохранения, отлавливать ошибки и предлагать переписать ф-цию и, конечно, это будет удобнее при '(lambda ...), а не "...".

а вообще непойму, почему в cl-store просто не добавят сериализацию для всех(пригодный) объектов

надо было так написать -

а вообще непойму, почему в cl-store просто не добавят сериализацию для всех(пригодный) объектов, а вместо этого делают нечто, претендующее на эту возможность в cl-store+functions:

The goal is to provide a simple, portable way to serialize functions.

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

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