LINUX.ORG.RU

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


2

2

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

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

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

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

Эм, неправильно выразился

Ну, само приложение, написанное на CL, которое работает в данный момент, и в который вносятся эти изменения

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

гораздо более интересный вопрос - при чем тут перекомпиляция

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

HMI на основе clg (биндинги к Gtk+, появились намного раньше cl-gtk2; вообще мне Gtk+ не очень нравится, думаю позже перейти на CommonQt)

интересно. а CommonQt не такое страшное как QtHaskell? в смысле, оно вообще юзабельное?

выложить это творчество где-нибудь на GitHub

было бы здорово

jtootf ★★★★★
()

LOR contest 2 ???

Ну давайте уже LOR contest ver. 2! А то столько переливания из пустого в порожнее! Особая жесть с примером парсинга логов апача :/

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

Под «это» я имел в виду «получить вектор инструкций и передать на них управление». Конкретно, вектор инструкций, а не функцию. Конкретно, передать управление, а не вызвать. В стандарте такого нет, но я уверен, что в любой open-source реализации за полдня можно накопать, как это сделать. Другое дело, нужно ли это.

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

И юзать в подходящих условиях.

это-то не вопрос, но вопрос-то не в этом :)

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

> интересно. а CommonQt не такое страшное как QtHaskell? в смысле, оно вообще юзабельное?

Имхо страшноватое, в связи с использованием #_ reader macro, но юзабельное. Я, впрочем, пока его ещё не очень сильно использовать пытался, так, посмотрел немного некоторое время назад и отправил автору (David Lichteblau) патч для поддержки интеграции со SLIME REPL — http://repo.or.cz/w/commonqt.git/commitdiff/ca95fa435cdc0ff4afe7aa761d2de03f0...

fionbio
()

archimag, где вас можно найти в IRC, Jabber, mumble или любом другом средстве более оперативного общения, чем на форуме?

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

Анонимусы не успокоились, им модераторы устроили локальный бан.

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

naryl, моя почта (и jid) на gmail, догадаться какая очень легко ;)

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

Технологически оправданную возможность, в случае C, я вижу только одну - это разделяемые библиотеки.

Ну конечно. Вот оно тайное знание лисперов о самомодифицируемом коде, выраженное на нормальном языке программирования:

#include <sys/mman.h>

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int f1(int q)
{
        return q;
}

int f2(int q)
{
        int a = q+2;
        return a;
}

int f3(int q)
{
        return 4+5;
}

typedef int (* f_t)(int );

int main()
{
        void * mem = 0;
        f_t  ff;
        size_t size = f3 - f2;
        mem = mmap(0, 4096, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_SHARED | MAP_ANONYMOUS, -1, 0 );
        memcpy(mem, f2, size);
        ff = f1;
        fprintf(stderr, "do %p -> result %d\n", ff, ff(1));
        ff = mem;
        fprintf(stderr, "do %p -> result %d\n", ff, ff(1));
        return 0;
}
$ gcc f.c
$ ./a.out
do 0x400574 -> result 1
do 0x7f3613664000 -> result 3

Ясно, что в memcpy можно загрузить код откуда угодно. Теперь интересно увидеть тоже самое на лиспе.

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

> typedef int (* f_t)(int );

Определяется тип int, который является разыменованием указателя f_t и применением к результату int? т.е. это рекурсивный тип, если я правильно понял. Разве C их умеет?

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

И *это* вы называете *нормальным* языком?

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

(defun foo () (write-line "Hello, world!"))

(defun bar () (foo))

(defun main ()
  (bar)
  (setf (symbol-function 'foo) (lambda () (write-line "FOO")))
  (bar))

(main)
;Hello, world!
;FO
Love5an
()
Ответ на: комментарий от naryl

т.е. это рекурсивный тип, если я правильно понял. Разве C их умеет?

Всё проще, здесь создаётся синоним типу - указатель на функцию, возвращающую int, принимающую в качестве параметра int.

Или это очередная зашифрованная сишная запись, дизайнер которой сделал всё возможное, чтобы её было невозможно правильно прочитать?

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

Так же вижу кучу инфиксных операторов, которые вычисляются в хз каком порядке и ещё большую кучу никому не нужных запятых и точек с запятой.

Это бред. Большинство языков имеют инфиксную форму записи, минимальное знакомство со остальным миром надо иметь, если непонятно как действиет сложение в инфиксной форме, не стоит вообще тогда обсуждать языки.

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

Теперь интересно увидеть тоже самое на лиспе.

Там красивее вышло -) нет адресной арифметики и, подозреваю, лисперы скажут точно, имеется проверка типов при вызове функции.

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

> Определяется тип int, который является разыменованием указателя f_t и применением к результату int? т.е. это рекурсивный тип, если я правильно понял.

Не, так определяется указатель на функцию.

Или это очередная зашифрованная сишная запись, дизайнер которой сделал всё возможное, чтобы её было невозможно правильно прочитать?

Запись вполне логичная :)

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

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

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

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

Расслабтесь, меня просто от общения с анонимусами плющит до сих пор :)

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

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

Аналогичный тайпдеф в D (да, я их умею читать ;]):

//typedef int (* f_t) (int );
  alias   int function(int) f_t;
naryl ★★★★★
()
Ответ на: комментарий от paranonymous

>Запись вполне логичная :)

Вот тут я думаю, что К&Р такую запись с бодуна придумали...

Логичная запись тут была бы какая-то такая:

typedef (int lambda(int))* f_t;

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

Лисперы такие лисперы. Зачем тут вообще функция bar?

(declaim (notinline foo)) 
 
(defun foo () (write-line "Hello, world!")) 
 
(defun main () 
  (foo) 
  (setf (symbol-function 'foo) (lambda () (write-line "FOO"))) 
  (foo)) 
 
(main)
NightmareZ
()
Ответ на: комментарий от NightmareZ

И вообще я не понял всего этого финта ушами. Ни на Си, ни на лиспе.

Подменили указатель (ссылку, etc.) на новую функцию. В чём прикол?

using System;

class Program
{
    private delegate void F();
    private static F _func;

    static void Main()
    {
        _func = () => { Console.WriteLine("Hello"); };
        _func();
        _func = () => { Console.WriteLine("World"); };
        _func();
    }
}
NightmareZ
()
Ответ на: комментарий от archimag

Потому что в Common Lisp есть не только мощь абстрагирования и можно обрабатываться текст по крайней мере хуже чем на Perl, а XML чем на C# (попутно выяснив, что программисты на C# ничего не смыслят в xml).

Лисп сломал тебе моск. Ты обобщаешь моё незнание XML на всех C# программеров. Это по-твоему логично, да?

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

>Ты обобщаешь моё незнание XML на всех C# программеров. Это по-твоему логично, да?

Да тут каждый второй «неасиливший лисп» проецирует своё отношение к лиспу на всё человечество. Хотя, требовать от них «логичности» аллогично ;)

yyk ★★★★★
()
Ответ на: комментарий от Waterlaz
alias    int function(int)   f_t;
typedef (int lambda  (int))* f_t;

Не правда ли похоже? Особенно если предположить что typedef (lambda)* function;

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

Некошерно...

Надо так:

 
(defparameter *foo* #'(lambda () (print "hello")))

(defun bar () (funcall *foo*))

(defun main () 
  (bar) 
  (let ((*foo* #'(lambda () (print "hello dynamic")))) 
    (bar)) 
  (bar))

(main)

;"hello" 
;"hello dynamic" 
;"hello"

)))

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

На Си мы исполнили бинарный код из области памяти в которую сами же этот бинарный код поместили. На лиспе сделали нечто другое.

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

Один лишь маленький вопрос: кошерно ли использовать CLOS так, как описано в PCL? С момента написания книги кардинальных изменений не произошло?

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

> Reset, а это: size_t size = f3 - f2; корректный, переносимый способ?

Нет, компилятор может переставить функции как угодно. Но суть в том, что внутрь mem мы можем положить любой код, в том числе и тот, который сами же скомпилировали.

Там красивее вышло -)

там была решена другая задача

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

>Ясно, что в memcpy можно загрузить код откуда угодно.

Совсем не ясно. Такой ход сработает только для простейших функций. А если функция использует относительную адресацию (PC-relative), что используется в position-independent-коде, то будет плохо.

Пример же Love5an'а будет работать в любом лиспе.

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

>> Один лишь маленький вопрос: кошерно ли использовать CLOS так, как описано в PCL?

Кошерно. Изменений не происходило с момента принятия стандарта.

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

Загрузить и исполнить новый бинарный код в процессе работы программы. Мы по-моему уже страниц 5 об этом говорим.

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

ага, скомпилировать статический код и просто его вызывать - и называть это самомодифицируемым кодом? вы хоть бы что-нибудь почитали-бы и не позорились.... Изобразите вот такое на С, с учетом того, что операция может вводиться откуда угодно - с клавиатуры, выбираться из таблицы в БД и т.д.

* (setq form1 '(+ 1 2 3 4))
* (eval form1)
10
* (eval (cons '* (cdr form1)))
24

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

> Я не вижу тут самомодификации, в терминах Си тут банальная подмена указателя на функцию.

Я не вижу самомодификации в C. В терминах Lisp тут банальное выполнение функции по имени (адресу в C). Где генерация в рантайме маш. кода, заменяющего имеющийся?

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

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

Так прокатит?

(defun f1 (x) (+ 1 x))
(defvar *f*)
(setf (symbol-function '*f*) (symbol-function 'f1))
(*f* 1)
(defun f1 (x) (+ 2 x)) 
(*f* 1)
(setf (symbol-function '*f*) (compile nil '(lambda (x) (+ 2 x))))
(*f* 1)
; 2
; 2
; 3
paranonymous
()
Ответ на: комментарий от Reset

>> Там красивее вышло -)

там была решена другая задача


А на C♯ третья.

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

>Один лишь маленький вопрос: кошерно ли использовать CLOS так, как описано в PCL? С момента написания книги кардинальных изменений не произошло?

Использовать однозначно кошерно.

С момента написания книги некоторые вещи поменялись. Например, использование MOP'а стало гораздо более переносимым и поддерживается практически всеми лиспами. Недавно совсем вышел filtered-dispatch, добавляющий интересный способ диспетчеризации методов.

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

> Где генерация в рантайме маш. кода, заменяющего имеющийся?

Можно вызвать отдельным процессом gcc && objcopy, а потом засосать это в буфер mem.

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

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

P.S. есть еще gnu lightning & LLVM, но они тоже отдельные библиотеки, и гемороя на порядок больше чем при использовании лиспа...

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

>> нет, я не вижу тут загрузки и исполнения нового бинарного кода

Его в С не видно. А тут compile как бы намекает на то, что берется код, компилируется в бинарник и исполняется на лету.

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

берется код, взятый откуда угодно -
из базы, из файл или из командной строки
(в данном случае это (lambda (x) (+ 2 x)))
потом компилится и линкуется к символу *f*
(грубо говоря теперь этот код принадлежит функции
с таким именем)

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