LINUX.ORG.RU

Emulek-style programming


2

1

Почитал я вот этот тред, и (может быть ошибочно) понял, что участники дискуссии разделились на 2 лагеря. Первый — за emulek-style, другие против.

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

Давайте оформим эту мысль вот так. Есть 2 ЯП l1 и l2. Есть транслятор с l1 в l2 — это компилятор, назовем его К, и есть транслятор с l1 в l1 — это интерпретатор — И.

Представим себе, что мы выполнили текст на языке l1 c помощью И

text(l1) --> И --> text(l1)
и с помощью K
text(l1) --> K --> text(l2)
Пока все вроде ок, все работает одинаково. А теперь представим себе такую ситуацию
(text(l1) --> И --> text(l1)) --> И --> text(l1)
Мы выполнили выходную строку текста как программу — подали ее вновь на вход транслятору. Иными словами мы выполнили сгенерированную в рантайме программу.

Может ли транслятор K сделать то же самое? Только с помощью костылей, типа макросов и препроцессоров. Но есть тонкий момент. Что если нам нужно сделать

((text(l1) --> И --> text(l1)) --> И --> text(l1)) --> И --> text(l1)
?

Тут у нас всплывает, ИМХО, суть того, что принято называть мощностью ЯП.

А Вы за Emulek-style или против?:)


phill  гуманитарий-норкоман
30.05.2014 13:58:20

не буду даже читать :)

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

Сегодня же не пятниц... Oh SHI~

У некоторых людей каждый день - пятницапоследний звонок.

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

Только eval eval'у рознь. Не везде он является эквивалентом исполнителя, не во всех яп он может выполнить произвольный кусок.

phill
() автор топика

Ослик как обычно херню писал.

Имхо, количество страниц показывает, что граница нечеткая. Наверное можно судить по рантайму после обработки: если вспомогательный (gc, dynamic dispatch, exceptions) - компилятор, если основной (нужно тащить все, кроме небольших частей (например, можно выбросить генератор байткода)) - интерпретатор.

Ну и интересны особые случаи: haskell/hint, мини-компилятор байткода (как часть интерпретатора), частичная специализация pypy, слои виртуализации jvm etc, sbcl/squeak (тоже непонятно куда: если говоришь интерпретация - где-то плачет лиспофанбой, с другой стороны рантайм жирнющий и не факт, что вспомогательный, вряд ли там грамотно отделено).

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

Ну и чо? Ты скомпилировал считанный текст, и исполнил его, что в этом удивительного? Это обычная компиляция.

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

Отрезали доступ к текущему контексту.

И как это ограничивает использование eval?

(defun bind-compile (vars values definition)
  (let* ((def (format nil "(lambda ~a ~a)" vars definition))
         (fun (compile nil (read-from-string def))))
    (apply fun values)))

(defmacro cbind (vars definition)
  (loop :for var :in vars
        :collect var :into vars
        :collect var :into values
        :finally (return
                  `(bind-compile (quote ,vars)
                                 (list  ,@values)
                                 ,definition))))

(defun test (foo)
  (let* ((bar 'the-bar)
         (fun (cbind (foo bar) "(lambda () (format t \"~a ~a~%\" foo bar))")))
    (funcall fun)))

(test 123)
; 123 THE-BAR

(test "Test")
; Test THE-BAR
korvin_ ★★★★★
()
Ответ на: комментарий от phill

Ну и чо? Ты скомпилировал считанный текст, и исполнил его, что в этом удивительного? Это обычная компиляция.

Ты же просил пример по-проще. Вот это он и есть.

korvin_ ★★★★★
()

есть транслятор с l1 в l1 — это интерпретатор

ВНЕЗАПНО, если из l1 в l1 - то не транслятор. Интерпретатор языка вообще не транслятор для него.

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

А так чо выводит? 1 или 2? Я пока непонел:)


(define z 1)
(define test (lambda(x) (let (y z) (eval x))))
(define z 2)
(print (test '(eval 'y))) ;2

phill
() автор топика
Ответ на: комментарий от MyTrooName

Это чушь полнейшая. Просто интерпретаторы имеют промежуточные стадии компиляции, а компиляторы — наоборот. Суть это не меняет.

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

Суть это не меняет

вот именно

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

MyTrooName ★★★★★
()

А мы за -20 норкоманам. Обкурятся какой-то херни и обдолбанные пишут на ЛОР.

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

А так чо выводит?

(defparameter *z* 1)

(defun test (x)
  (let ((y *z*))
    (ceval (y) x)))

(defparameter *z* 2)

(print (test '(ceval (y) 'y)))
; 2

Я пока непонел:)

Да я уже догадался, что ты тугой как валенок.

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

А, так это Вы называете то же самое??? Я в осадке. Стоит ли продолжать. Может сразу написать интерпретатор, запускать из компилятора, и читать? LOL И даже при всех костылях — не first-class. Это, сука, точно, emulek-style, не больше не меньше.

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

А, так это Вы называете то же самое?

Вполне. В чем отличия?

Я в осадке. Стоит ли продолжать.

Куда уж дальше после осадка?

Может сразу написать интерпретатор, запускать из компилятора, и читать?

Зачем?

И даже при всех костылях — не first-class

Что именно тут не first-class? ceval потому что макрос? Используй bind-eval; ceval просто сахар.

korvin_ ★★★★★
()

Сам разобрался бы сначала

(loop)

интерпретируется, но никуда не транслируется (так что l1 -> l1 не получится).

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

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

А типичный ЯП может сначала компилироваться в IR (тут всё является трансляцией, включая какие-то частичные вычисления), этот IR потом выполняется (это не трансляция).

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

Ладно, я не силен в CL, мне сходу не разобраться. Напомню, что изначально речь шла о том, что eval неполноценен. Вы мне начали объяснять как накостылить имитацию. Где то eval, где то ceval, где-то huyeval, а там где надо first-class — чрезжопные методы рулят, ага. Да еще доставляет то, что я обо всем заранее должен позаботиться, вплоть до того, что объявляя переменную должен думать, как я в дальнейшем буду ее использовать. Тогда как в интерпретаторе есть универсальность и простота иcкаропки.

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

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

А так вообще - думать не надо, что с переменными делать? Вон из профессии.

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

Напомню, что изначально речь шла о том, что eval неполноценен.

Ну так продемонстрируй на практике эту неполноценность.

Где то eval, где то ceval, где-то huyeval

Зачем? Можешь везде использовать ceval, разрешаю.

а там где надо first-class — чрезжопные методы рулят, ага.

Обычные методы. Черезжопность — это использование eval вообще.

Да еще доставляет то, что я обо всем заранее должен позаботиться

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

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

А обычно ты не думаешь, просто объявляешь переменные, просто чтобы были?

Тогда как в интерпретаторе есть универсальность и простота иcкаропки.

Эта «коробка» — одна короткая функция.

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

интерпретируется, но никуда не транслируется

транслируется. Вот Вам простейший метациклический интерпретатор:

(define eval
  (lambda(expr)
    expr))
(define repl
  (lambda()
    (write (eval (read)))
    (repl)))
На каждой итерации loop возвращает себя же в виде текста в REPL. Транслятор пишет что то, исполняет, затем читает результат, и так по кругу.

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

А мы за -20 норкоманам. Обкурятся какой-то херни и обдолбанные пишут на ЛОР.

Причём можно даже выдавать исключительное модераторское право разным людям резать топики в определённом разделе по причине «наркомания в плохом смысле этого слова».

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

Транслятор это просто алгоритм

Алгоритм тут слишком расплывчато, скорей абстрактная машина вкупе с алгоритмом.

который за конечное время превращает элементы одного языка в элементы другого определённым образом

Проще говоря, переписывает текст. Это и есть компиляция.

(сохраняя семантику)

Какую семантику? В случае компиляции никакая семантика не сохраняется. Есть лишь забота о том, чтобы выходной текст был корректной программой для target-исполнителя. Семантика си и исполнителя кода, в который он компилируется, как бы, отличается, мягко говоря.

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

Вам

Можно без этого :)

Ты написал eval = id, так что я его выкидываю, остальное:

void repl() {
    for (;;)
        write(read());
}

то есть чтение (пусть строки) с последующей печатью (её же) в бесконечном цикле.

Это не имеет отношения к тому, что в L-языке есть программа "(loop)" которая L-интерпретатором выполняется сколько угодно долго, но никуда не транслируется. Она _может_ каким-то транслятором переводится в программу на T-языке (которую может выполнять, не транслировать, T-интерпретатор).

Чем отличается компилятор от интерпретатора? (комментарий)

З.Ы. и eval у тебя неправильный, так как он игнорирует семантику "(loop)" — я привожу пример программы которая выполняется сколь угодно долго, так что eval должен выполнять её сколь угодно долго, а не быть id.

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

просто объявляешь переменные, просто чтобы были?

Хватит придуриваться, ты понял о чем я. Да, в нормальном языке, переменная — это просто переменная а не динамическая/статическая/элитарная/специальная. Нормальный дизайн ЯП не предусматривает обилие сущностей, их появление свидетельствует об уродливом дизайне. Достаточно взглянуть на поделие страуса, чтобы в этом убедиться.

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