LINUX.ORG.RU

Приходилось ли вам писать на Лиспе?


2

2

Ну, что ж, в Development так в Development, хотя Лисп давно перестал быть мемом одного лишь Development'а (и даже одного ЛОРа). Итак, сабж!

[ ] Да, профессионально и за деньги
[ ] Да, just for fun и для самообразования
[ ] Да, участвовал в opensource-проекте
[ ] Да, пилил скрипты Emacs/GIMP/AutoCAD/Lilypond etc.
[ ] Да, в рамках образовательной работы (лаба, курсовик, диплом)
[ ] Да, в рамках академической работы (диссертация, статья, монография)
[ ] Да, мне сказали, что лисперов любят девушки
[ ] Нет, но собираюсь
[ ] Нет, и не собираюсь
[ ] Вообще-то я Джон МакКарти, а вы кто такие?
[ ] в Советской России Лисп пишет на тебе!

Приветствуются развернутые ответы и верифицируемые пруфлинки. Например, на какую фирму работали, в каком конкретно opensource-проекте участвовали, какая была тема научной работы, помогло ли с девушками, и тому подобное. INB4 буквоедов: под «лиспом» подразумеваются все языки семейства: Scheme, CL, Clojure и прочие.

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

> Кодогенерация вообще мало где нужна ;)

Если такая как в C#, то безусловно, таким без совершенно крайней на то необходимости никто заниматься не будет.

archimag ★★★
()
Ответ на: комментарий от archimag
(defmacro defhello (str) 
  `(defun ,(intern (format nil "HELLO-~:@(~A~)" str)) () 
     (print ,str))) 
 
(defhello "NightmareZ") 
 
(hello-nightmarez)
defhello :: String -> Q Exp
defhello str = [| $(defhello' [| str |]) |]
    where defhello' str = [| print $ "Hello, " ++ $str |]

*THTest Language.Haskell.TH> let helloNightmarez = $(defhello "NightmareZ")
*THTest Language.Haskell.TH> helloNightmarez
"Hello, NightmareZ"
jtootf ★★★★★
()
Ответ на: комментарий от archimag

Если такая как в C#, то безусловно, таким без совершенно крайней на то необходимости никто заниматься не будет.

А зачем в повседневной практике кодогенерация? Даже, если она очень красиво реализована.

NightmareZ
()
Ответ на: комментарий от jtootf
defhello :: String -> Q Exp 
defhello str = [| $(defhello' [| str |]) |] 
    where defhello' str = [| print $ "Hello, " ++ $str |] 
 
*THTest Language.Haskell.TH> let helloNightmarez = $(defhello "NightmareZ") 
*THTest Language.Haskell.TH> helloNightmarez 
"Hello, NightmareZ"

~

hello :: String -> IO ()
hello str = print $ "Hello, " ++ str

*THTest Language.Haskell.TH> let helloNightmarez = hello "NightmareZ"
*THTest Language.Haskell.TH> helloNightmarez
"Hello, NightmareZ"

а можно и вот так, и безо всякой кодогенерации

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

> а copy-seq что делает? т.е. что делает по названию понятно, но зачем?

Ну дык, что бы защититься от изменений переданной строки в другом месте, CL ведь не ФП ;)

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

Ну вот ты для чего ее использовал?

когда пишу на Tcl - использую повсеместно; в своё время на шаблонах C++ писал генераторы (там, правда, в основном ради type safety - чтобы не использовать void*)

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

> А зачем в повседневной практике кодогенерация? Даже, если она очень красиво реализована.

Затем, что автоматически сгенерённый из модели код намного лучше и надёжнее, чем написанный живым человеком. Модель какой угодно может быть, от структуры БД и до конечных автоматов, логических выражений, диаграмм и прочей фигни.

lisprocks
()
Ответ на: комментарий от jtootf
(defmacro defhello (str)  
  `(defun ,(intern (format nil "HELLO-~:@(~A~)" str)) ()  
     (print ,str)))  
  
(defhello "NightmareZ")  
  
(hello-nightmarez)
proc defhello {name} { return "puts \"Hello, $name\"" }

proc helloNightmarez {} { {*}[defhello "Nightmarez"] }

(tcl) 1 % helloNightmarez
Hello, NightmareZ

не удержался :)

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

>А зачем в повседневной практике кодогенерация?

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

yoghurt ★★★★★
()
Ответ на: Отстой! от yoghurt

Чиста поржать:

st> | b |
st> b := Behavior new.
a Behavior
st> (b compile: 'square: anInteger [ ^ anInteger * anInteger ]') inspect
An instance of CompiledMethod
  header: 65
  Header Flags: 
    flags: 0
    primitive index: 0
    number of arguments: 1
    number of temporaries: 0
    number of literals: 0
    needed stack slots: 8
  descriptor: a MethodInfo
  byte codes: [
    [1]	source code line number 1
	push Temporary[0]
    [3]	push Temporary[0]
    [5]	send 1 args message #*
    [7]	return stack top
  ]
<no name>>>square:
yoghurt ★★★★★
()

[ ] Да, участвовал в opensource-проекте
[ ] Да, пилил скрипты Emacs/GIMP/AutoCAD/Lilypond etc.
[ ] Да, в рамках образовательной работы (лаба, курсовик, диплом)

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

> PROT_READ | PROT_WRITE | PROT_EXEC, MAP_SHARED | MAP_ANONYMOUS
Разве это переносимый код? Я не знаток С, но я почти уверен что это не С вообще, а конкретная реализация С и/или конкретная платформа.

На лиспе сделали нечто другое

Да, на лиспе сделали гораздо больше: не только поместили код и исполнили его, но и сгенерировали. Зачем нужно помещать код, если мы не можем его сгенерировать? Откуда мы его возьмём? Для всех мыслимых мной практических задач, где нужна/полезна самомодификация, нужно сначала динамически сгенерировать код, потом поместить, потом исполнить. Только все эти этапы вместе, но не по отдельности. Вы же не можете привести пример динамической генерации машинного кода на С?

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

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

> А зачем в повседневной практике кодогенерация?
Из моей практики и того, что я близко видел:
1. Генерация SQL запросов. Для разного рода статистики зачастую невозможно статически определить SQL запрос, возвращающий нужный набор данных. Да и для пользовательского интерфейса тоже.
2. Аудит/история. В тех же SQL СУБД часто бывает нужно хранить историю изменений таблицы. Самый эффективный способ здесь - это кодогенерация.
3. Интерфейсы. Имеется N хранимых процедур на сервере. Желательно создать интерфейс к каждой из них, позволяющий проверять правильность передачи параметров в клиентском языке и производить преобразование типов аргументов.
4. компонентные архитектуры (я работал только с COM). Кодогенераторы обычно входят в состав инструментальных средств. Если не входят - нужно быть ручным кодогенератором.
5. ./conigure и весь класс таких задач
6. Повторяющиеся образцы кода, например:
module_do_something(...)
if (module_error!=0) {
writeln(«error %d», module_error);
return -1;
}

Хотя это скорее больше похоже на макросы (которых нет, а должны быть).

7. AJAX
8. Реализация SQL сервера. Получаемый декларативный запрос преобразуется в некий процедурный код.
9. Компиляция и трансляция. Код на языке высокого уровня преобразуется в код на языке низкого уровня.
10. Qt фактически содержит препроцессор, потому что «великий и могучий» С++ на практике недостаточно «велик и могуч».

Думаю, хватит :)

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

> Я не знаток С, но я почти уверен что это не С вообще, а конкретная реализация С и/или конкретная платформа.

Это работает на любой posix системе. На венде надо использовать VirtualAlloc.

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

Что стоит за этими самыми compile, load и т.п. ?

По-моему, это переусложнение. Попробую объяснить предельно просто. Давайте рассмотрим просто SBCL и просто DEFUN. Например, вводим в подсказке интерпретатора SBCL следующее:

CL-USER> (eval (read)) ; прочитай код с консоли и выполни его. 
; теперь вводим следующее
(defun foo (x) (+ x 1)) ; это код. Он динамический, т.к. мы его напечатали во время исполнения реализации лиспа
; интерпретатор напечатает:
FOO
; т.е., он создал именованную функцию foo
CL-USER> (foo 5) ; проверим, работает ли? 
6 ; да. 
CL-USER> (foo "УйХ")
; выдаёт ошибку типизации
CL-USER> (disassemble foo) ; что за код? 
; БЛА-БЛА-БЛА (выдаёт ассемблер)

Где простейшая низкоуровневая конструкция типа такой (setq f '\55\48\89\e5\89\7d\ec\8b\45\ec\83\c0\02\89\45\fc\8b\45\fc\c9\c3')

Если такой код есть на С, несложно вызвать его из лиспа. Также несложно вызвать лисп из С. Для такой деятельности не нужно знать потроха лиспа, т.к. они гораздо сложнее, чем потроха С. Нужно учитывать такие вещи, как треды и сборка мусора. Поэтому, логичным будет выстроить себе кусочек С внутри лиспа и работать с ним.

(defcfun "qsort" :void
    (base :pointer)
    (nmemb :int)
    (size :int)
    (fun-compar :pointer))
   
(defcallback < :int ((a :pointer) (b :pointer))
    (let ((x (mem-ref a :int))
          (y (mem-ref b :int)))
      (cond ((> x y) 1)
            ((< x y) -1)
            (t 0))))
   
CFFI> (with-foreign-object (array :int 10)
          ;; Initialize array.
          (loop for i from 0 and n in '(7 2 10 4 3 5 1 6 9 8)
                do (setf (mem-aref array :int i) n))
          ;; Sort it.
          (qsort array 10 (foreign-type-size :int) (callback <))
          ;; Return it as a list.
          (loop for i from 0 below 10
                collect (mem-aref array :int i)))
Он показывает, что легко делается интерфейс с любым кодом на С. В т.ч., и с кодом, который выполняет вектор инструкций, если таковой код на С имеется. Но, опять же, неясно, зачем это может понадобиться. Ведь код мало исполнить, нужно его сначала сгенерировать.

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

Где простейшая низкоуровневая конструкция типа такой (setq f '\55\48\89\e5\89\7d\ec\8b\45\ec\83\c0\02\89\45\fc\8b\45\fc\c9\c3')

Например так

(setq f  
      (let ((bin-code #(#x55 #x48 #x89 #xe5 #x89 #x7d #xec #x8b #x45 #xec #x83 #xc0 #x02 #x89 #x45 #xfc #x8b #x45 #xfc #xc9 #xc3))) 
        (with-foreign-object (array :int (length bin-code)) 
          (loop for i below (length bin-code) 
             do (setf (mem-aref array :int i) (aref bin-code i))) 
          (lambda () (foreign-funcall-pointer () array))))) 

И никакого C. Полный аналог версии с memcpy.

monk ★★★★★
()

[v] Да, just for fun и для самообразования
Писал небольшие программки вроде вычисления факториала разными способами на Common Lisp.

Xenius ★★★★★
()

[x] Вообще-то я пишу на брейнфаке!

usbmonkey
()

итоги уже подвели?

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