LINUX.ORG.RU

eval и наследование

 ,


0

4

А не обращали ли вы внимания на такой любопытный факт. Мы можем определять свои функции eval, которые специализируют, или «затирают» способы обработки входных данных, примерно таким вот образом

myEval1 = function(expression){
 if(somePredicat1(expression)) return doSomething1
 eval(expression)
}
//далее
myEval2 = function(expression){
 if(somePredicat2(expression)) return doSomething2
 myEval1(expression)
}
данный подход, фактически воспроизводит цепочку наследования ООП с делегированием. eval<-Eval1<-Eval2 — тут eval является верхним класом, анологичным Object во многих яп, а expression - сообщением. Тут только нет диспетчеризации на уровне интерпретатора, но это, тем не менее, семантика Ъ-ООП языков в первозданном виде! Eval — это объект. Правильнее его было бы назвать Evaluator. Все его наследники — объекты. Если, скажем, со старых лиспов снять мишуру, они будут ООП языками! И очевидно, что в основе их именно ООП-подход, а вовсе не ФП, как это принято считать. Просто тогда не было этого слова.

Под мишурой я тут понимаю в первую очередь quote. На самом деле, я думаю, именно это соображение повлияло на идеи Алана Кея. За основу он брал не Eval, а фекспры, но это, тащемта, анлогично. Он говорил что-то типа: «я много раз задавал вопрос, почему нужно энергично вычислять аргументы? почему бы все не вычислять принимающей стороной? И никогда не получал на это внятного ответа...» Если бы у нас все выражения выполнялись лениво, у нас бы не было необходимости что-либо квотировать, однако мы не потеряли бы в выразительности. Функция quote — является пятым колесом. Если бы ее не было, нам достаточно было бы для всех вычислений что-то типа ULAMBDA и НЕквотированных строк (или списков), которые в контексте ООП — сообщения. Мы смогли бы выбросить из элементарного лиспа lambda и quote и eval(заменив его ULAMBDA) абсолютно безболезненно, а так же еще кучу связаной с этим мишуры. Лисп Маккарти — это не простой концептуально язык, он попадает под бритву Оккама!



Последнее исправление: callbackhell (всего исправлений: 4)

Он говорил что-то типа: «я много раз задавал вопрос, почему нужно энергично вычислять аргументы? почему бы все не вычислять принимающей стороной? И никогда не получал на это внятного ответа...»

В реболе можно так:

>> f: func [x 'y] [
print x
print y
]
>> f (5 + 5) (5 + 5)
10
5 + 5
loz ★★★★★
()
Ответ на: комментарий от loz

Да, сразу не понял, думал это обычное квотирование:) В Io, кстати, тоже так можно.

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

Это уже вопрос того какой дефолт, то есть вопрос стиля. Я хотел сказать, что невычисление аргументов это просто еще одна исторически не прижившаяся практика, ничего сверхъестественного в ней нет.

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

Тут можно рассуждать так: ленивые функции могут заменить энергичные, а наоборот не прокатит без лишней сущности - quote.

Например, если у нас лень, ты определяешь какую-то функцию, затем чтоб пропарсить эту функцию, ты просто подаешь ее на вход другой функции. У тебя сохраняется эквивалентность кода и данных. Чтоб провернуть ту же самую операцию при энергичных вычислениях, тебе надо определять всегда не функцию, а квотированную функцию, и при необходимости, ее явно евалить. Становится гораздо сложней, так как обычно ты не квотируешь функции. Соответственно, у тебя в одном случае, код всегда доступен для интроспекции и рефлексии, а в другом тебе надо всегда забивать голову, что тебе квотировать, а что нет. В итоге, все экспонцеально усложняется.

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

Поэтому, это не просто традиция. Это 2 противоположнх полюса.

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

не понял, о чём ты,

но кажется о фекспрах и окружениях как первоклассных объектах в духе kernel, vau-exprs и 3-Lisp.

к примеру, почему у нас 2 метавычислителя eval-apply, «пренотации и эмблемы», а не 3: eval-apply-locus (здесь locus — вычисление «места памяти» , окружения, скорее всего пренотация; эмблема — eval, но «чувственный», образный, многомерный — то есть, в нужном окружении, переданном как первоклассный объект).

а вообще лямбда куб и развёртка 3D по плоскостям 2x 2D.

anonymous
()
Ответ на: не понял, о чём ты, от anonymous

Нет, я, в данном случае, не совсем об этом. Я о том, что можно было бы сделать элементарный лисп, аналогичный Lisp 1.5 Маккарти, и выкинуть из него (энергичную)lambda и quote, как минимум, и он сохранил бы выразительную силу. Энергичные вычисления в лиспе избточны, они не нужны. И они концептуально усложняют язык, это лишние сущности.

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

выкинуть из него (энергичную)lambda и quote, как минимум, и он сохранил бы выразительную силу.

(funcall
  (let ((fbody '(lambda (x y) (cons x y)))
    (eval (cons 'lambda 
             (cons '(y x)
                 (cddr fbody)))))
  #'car #'cdr)
; вернёт (#'cdr . #'car)

Как напишешь на твоём лиспе без quote?

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

под рукой лиспа нет, поэтому покажу на Io



method(
  doString(
   call message arguments at(0)\
   asString asMutable replaceFirstSeq("x, y", "y, x") 
  ) call(1, 2)
) call(method(x, y, list(x, y))) print



#>>>> list(2, 1)

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

А вообще, касаемо конкретно Io, учитывая то, что Io — ООП язык, и в нем есть сообщения, можно это проще написать, человеческим кодом.

method(x, y, list(x, y)) setArgumentNames(list( "y", "x")) call(1, 2) 

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

asString — это метод типа «Message», возвращающий тип «String», проще говоря, конвертирует сообщение в строку. Суть в том, что метод сам ленив, для него квотировать ничего не нужно. В Io вообще нет энергичных функций, все выполняется на принимающей стороне. Т.е. нет аналога lambda. А строка, да, аналог квот, это «более привычно», но могло бы быть myString call, как в тикле и баше $string это синтаксические мелочи.

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

Тут еще дело в том, что надо как то синтаксически отделять строку от сообщения.

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

В чем тут подвох. мы по дефолту либо квотируем и вполняем, либо не квотируем и выполняем. То есть, либо интерпретатор эвалит, либо мы вручную эвалим. Если мы вручную эвалим, мы можем добавлять управляющие конструкции, которые будут работать в рантайме. Каждая функция у нас становится эвалюэйтером. А в лиспе сразу 3 непонятные хрени. Это происходит оттого, что у нас под ковром сначала дефолтно эвалится квотированный список или символ в *просто* список или символ, а потом этот список или символ эвалится как выражение. Это пятое колесо, тавтология. Фэкспры работают концептуально правильно. они берут сразу выражение as is, но их как известно выпилили, так как «Normal considered harmful» — (С)A. Key

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

модель исполнения лиспов, несмотря на весь пиар, ничуть не мощней джаваскриптовской. Макросы — это тупые шаблоны. Ты можешь для JS написать шаблонизатор, и проходить им сырой исходник, и у тебя будут такие же макросы, как в лиспе, за исключением синтаксиса. И даже в рантайме можно будет делать кодогенерацию, если твой шаблонизатор написан на самом JS, ты будешь просто делать (eval (preprocess (string))), а парсинг структур тупо заменяется регулярками, даже удобней, или накрайняк самописным парсером. И получаем в итоге тот же самый лисп, вид сбоку.

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

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

В джаваскрипте во время компиляции нельзя исходник обрабатывать. В IO вообще компилятора нет.

а парсинг структур тупо заменяется регулярками

Даже HTML регулярками не парсится.

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

Написать свой парсер, свою среду обработки исходника и запуска компилятора... «Любая достаточно сложная программа на Си или Фортране содержит заново написанную, неспецифицированную, глючную и медленную реализацию половины языка Common Lisp.» (с) Гринспен

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

Время компиляции, с точки зрения пользователя не имеет значения. Дедо не в том, что-что-то делается на этапе компиляции, а в том, что это делается перед исполнением (eg тайпчекинг, макроэкспанд), поэтому работа с кодом на этапе перед исполнением возможна даже в языке который не компилируется вообще.

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

Дедо не в том, что-что-то делается на этапе компиляции, а в том, что это делается перед исполнением (eg тайпчекинг, макроэкспанд),

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

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