Category: it

Category was added automatically. Read all entries about "it".

glider

про ООП - 2

Я вот сейчас с ребе sorhed обсуждал и выяснил, что мне больше всего нравится в Скале. Ее система модулей основанная на объектах и миксинах. Объектно-ориентированная система.

Читал на днях недавнюю паперу First-Class Modules for Haskell, где рассказывается про то, как SPJ с товарищем добавляют Scala-like (ну, или ML-like, как кому приятнее) систему модулей в Хаскелл. Вслед за авторами сравнивал этот подход с Nested Types - основополагающей паперой Одерского.

Как я понял, все решают одну и ту же проблему. Как сделать так, чтобы: 1) был модуль Set с функциями empty, add и asList, 2) внутреннее представление множества (структуры данных, возвращаемой empty, и манипулируемой остальными функциями) было скрыто, 3) можно было писать s.add 1 s.empty и все тайпчекалось.

Это вполне можно сделать без объектов - как показывает практика ML и схема, описанная в папере про Хаскелл. Внутреннее представление скрывается за экзистенциальным типом (абстрактный тип в ML или экзистенциальный тип в расширенном Хаскелле), в язык добавляется конструкция, которая говорит, что у s.add и s.empty совместимые типы (manifest types в ML или open в расширенном Хаскелле) - все, готово, можно юзать.

Здорово то, как это сделано в Скале. Модули (они же objects ака singleton types) + абстрактные типы (они же abstract type members) + self-types или явные type refinements. Под капотом там тот же самый матан с экзистенциальными типами (чтобы убедиться, можно почитать вышеслинкованную паперу Nested Types), но выглядит это все как кейк паттерн на всем привычном.

Из ООП взята инкапсуляция как понимание того, что есть первоклассная сущность - модуль, он же объект - внутри которого находятся штучки (в данном случае, типы и термы). Взято наследование (ака subtyping) в плане того, что для абстрактных типов можно задавать upper bounds и в плане того, что сущности можно смешивать вместе при помощи миксин-композиции. Про полиморфизм можно много чего подогнать. Например то, что неважно, что именно под капотом абстрактного типа - главное, что все, кому надо, умеют с ним работать (через функции модуля или через функции из upper bound), поэтому подкапотное содержимое можно удобно заменять.

В итоге: ФП-шный матан теории типов скрестили с идеями из ООП - получилась Скала. Матан остался только под капотом, а фасад оказался "объектно-ориентированный", в результате чего получилась гибкая (наппример, на кейке без привлечения дополнительных языковых средств можно сделать виртуальные классы), но простая для восприятия система. upd. Хорошая иллюстрация к посту есть вот тут: http://maxim.livejournal.com/393915.html.
glider

рефлекшн

Последние пару месяцев я подзабросил ЖЖ, поэтому поделюсь статус апдейтом.

Reflection API оказался очень крепким орешком и его пришлось полностью переписать, причем переписывание затронуло гигантский кусок компилятора (около 20к строк кода). Вот документ, частично описывающий результаты работы: https://docs.google.com/document/d/1Z1VhhNPplbUpaZPIYdc0_EUv5RiGQ2X4oqp0i-vz1qw/edit.

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

Таким образом, рефлекшен можно делать кучу вещей, которые умеет компилятор. Например: 1) посчитать является ли какой-то тип подтипом другого типа, 2) вернуть сигнатуру метода со всем наворотами Скалы (имплиситами, множественными списками параметров), 3) тайпчекнуть динамически сгенерированный сниппет кода и так далее. Более подробно вот тут: http://scalamacros.org/talks/2012-05-19-ScalaReflect.pdf (конкретные детали уже устарели, но общая картина не изменилась).

Еще я крайне горжусь методом typeOf, который мы совсем недавно добавили в Скалу. Теперь можно просто написать typeOf[List[Int]] или что-нибудь навороченное вроде typeOf[{ def foo(x: Int): Int}] - и метод вернет тип, в точности соответствующий типу в квадратных скобках. Под капотом там адовая жесть - реификация, тайп теги, бодяга с класслоадерами, но программисту этого не видно, и все просто работает (ессно, каждый аспект адовой жести можно кастомизировать, но мы сейчас говорим про 95% юзкейсов). Я несказанно рад видеть вопросы на стаковерфлове от челов, которые не в курсе базовых вещей в рефлекшене, но зато бодро рассекают с тайп-офом, и он у них работает. Реально, реификация предполагась самой трудной для понимания в новом API, а вот оно как сложилось.

В целом, все позитивно, кардинальных изменений на горизонте не предвидится, осталось только пофиксить 90+ багов, которые на мне висят :)
glider

Квазицитаты, метауровни и всякая всячина

В последнее время меня увлекли квазицитаты, поэтому я отложил сторонку допиливание макросов и начал разбираться с КЦ (кстати, это меня поражает в нашей лабе, и я, похоже, уже заразился этой привычкой - куча народу просто занимается тем, что в данный момент интересно, без особого плана или принуждения себя делать что-то конкретное). На всякий случай вот недавний коммит: https://github.com/scalamacros/kepler/commit/28be76ac3f2893a12898eabca139e27d2b166a8b, но сейчас я постараюсь рассказать человеческим языком.

С давних времен (2.8+) у нас в компиляторе поддерживается экспериментальный Code.lift, который превращает кодяру внутри единственного параметра в эквивалентный AST, который можно проинспектировать в рантайме (аля Expression Trees в сишарпе). С появлением reflection api, динамической кодогенерации и макросов настало время причесать лифтинг и добавить ему туда одну штучку, которая абсолютно необходима для удобной работы с деревьями. Ага, точно - я имею ввиду сплайсинг. Про него и про интересные эффекты, которые им порождаются, и будет сегодняшний пост.

***

Немного введения. Лично я лучше всего учусь на примерах, поэтому вместо тонны слов про то, что такое квазицитаты и сплайсы, вот небольшой сниппет, который заодно проиллюстрирует нашу реализацию. Итак, в моем бранче scalac можно писать вот так:
def two = lift{2}                                   // Constant(Literal(2))
def four = lift{splice{two} + splice{two}}          // Apply(Select(two, newTermName("$plus")), List(two))

val reporter = new ConsoleReporter(new Settings)    // немного бойлерплейта - мы пока не заморачивались над API
val toolbox = new ToolBox(reporter)                 // само собой, к релизу 2.10 все будет более приятно в использовании
                                                    
val ttree = toolbox.typeCheck(four.tree)            // тайпчекает дерево из four, после этого вызова можно 
                                                    // пробежаться по результату и узнать типы фрагментов
                                                    // а также увидеть, к каким именно внешним символам что прибиндилось
                                                    // к примеру, если бы в лифченном коде мы вызывали println, то
                                                    // sym.fullName для println после тайпчека показал бы scala.Predef.println

println(toolbox.runExpr(ttree))                     // запускаем компилятор, минуя первую фазу, parser,
                                                    // результаты тайпчека будут стерты нафиг, т.е. предыдущая строчка была необязательна
                                                    // на выходе будет сгенерирован in-memory байткод
                                                    // который будет подхвачен и исполнен специальным класслоадером
Как можно видеть, лифт преобразует кодяру в соответствующий AST, который можно проанализировать, тайпчекнуть и даже исполнить в рантайме. Более подробно про скаловский AST можно почитать у Мигеля Гарсиа (http://www.sts.tu-harburg.de/people/mi.garcia/ScalaCompilerCorner/UntanglingScalaASTs1ofN.pdf), а я лишь замечу то, что, в отличие от сишарпа, меня порадовало небольшое количество и гибкость стройматериалов. Например, нет разделения на Call и Invoke - есть Select, который достает мембер по имени (в том числе это работает и для методов), а есть Apply, который применяет функцию к аргументам (неважно, делегат это или метод).

Даже сам по себе лифтинг очень интересен. Его реализация в сишарпе весьма ограничена (лифтятся только лямбды + в процессе лифтинга теряется информация о переменных, захваченных из лексического скоупа), но все равно он стал очень популярен для создания type-safe апи. Однако, поработав с деревьями выражений сишарпа, довольно быстро сталкиваешься с необходимостью собирать деревья из динамических кусочков. К сожалению, лифтинг здесь не помогает (ибо он работает только с тем, что известно во время компиляции) и приходится вручную конструировать деревья.

Проблема композиции деревьев решается при помощи сплайсинга. В примере выше мы берем ранее залифченный код (переменную two) и вставляем его в квазицитату (выражение под вторым лифтом). В результате компилятор создаст ссылку на two, а также сгенерирует дерево, соответствующее шаблону, в который мы вставляем two. На самом деле, компилятор сделает еще больше - так как тип переменной two известен (он выводится как Code[Int]), то мы знаем, что сложение в four будет соответствовать сложению двух интов, т.е. обе квазицитаты в примере будут статически тайпчекнуты!

Получается все очень симпатично и концептуально просто так что я бы на этом и закончил, но самое интересное только начинается!

***

Во-первых, а что, если перед тем, как что-то сплайснуть, мы хотим это что-то обработать напильником? Каноничный пример - printf. Перед вставкой аргумента в принт мы, возможно, захотим его отформатировать, например, обернув в Apply(Select(arg, "format"), List(...)). Пока что ничего страшного, ибо спецификаторы формата задают тип аргумента, поэтому результирующее дерево все еще можно типизировать.

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

Для спасения ситуации многие системы метапрограммирования вводят понятие нетипизированных квазицитат. К примеру, F#. Или вот Немерле, в котором макросы и квазицитаты по умолчанию нетипизированные (правда, с опциональными аннотациями типов). Более подробно об этом дизайн-решении написано в диссере одного из создателей Немерле: http://nazgul.omega.pl/macros.pdf (см. главу 8.1.1 "Static typing vs run-time").

Ту же самую штуку я добавил в Скалу, но возникло небольшое затруднение. Очень хочется типизировать все по макисмуму (например, если в кц есть типизируемые фрагменты, то есть желание их проверить), но для этого надо вводить в систему типов специальный магический тип (в слинкованном выше патче я так его и назвал - Magic). Этот тип, прикасаясь к чему угодно, преобразует это что угодно в Magic. Логично в принципе - если мы вызываем метод у результата нетипизированного сплайса, то мы не можем типизировать этот вызов и вынуждены отложить решение до рантайма. А пока что надо убедить компилятор отвязаться. Очень интересно, есть ли для этого формализация, а то пока что мой подход уж сильно ад-хок.

***

Во-вторых, в честь того, что мы сделали стейджинг крайне легким (вызов магической функции - что может быть легче) и сняли все тормоза (программист может вызвать лифт/сплайс откуда угодно), перед нами начинает маячить знаменитая темная башня метауровней (вот мой миррор статьи, оригинал вроде бы сдох: http://dl.dropbox.com/u/10497693/Library/Computer%20Science/Metaprogramming/Macros/Quasiquotations/Metalevels/The%20Dark%20Tower%20of%20Meta-levels.html):



Дело в том, что метауровни логически разделены между собой, а мы только что дали программисту элементарную возможность их смешать в кучу при помощи лексических скоупов. Смотрим еще один пример:
def y: Tree = ...
lift {
  y;                 // metalevel 1 refers to metalevel 0 => okay, but need a translation
                     // we will generate something like: Ident(newTermName("y"))

  splice { y };      // metalevel 0 refers to metalevel 0 => okay, no need of a translation
                     // we just insert a reference to y in the tree generated in LiftCode
                     // so that the generated code will look like: y (yep, as simple as that)

  def x: Tree = ...

  x;                 // metalevel 1 refers to metalevel 1 => okay, no need for a translation
                     // just Ident(newTermName("x"))

  splice { x };      // metalevel 0 refers to metalevel 1 => uh-oh, no translation will help us
                     // exact value of x will be known only during the run-time
                     // so we can only perform the splice during the run-time
                     // for the state of the art JVM it's more like science fiction
}
Итак мы только что убедились на практике, что: а) метауровни могут использовать переменные предыдущих метауровней, б) метауровни не могут ссылаться на переменные старших метауровней. Надо как-то закодировать это ограничение в компиляторе, и для этого мы снова воспользуемся типами (по крайней мере, на это настроен Адриаан, мнение Мартина пока что узнать не удалось).

Основная идея заключается в том, чтобы кодировать метауровень символов (символ = переменная, функция, класс - все, что угодно, что можно объявить) в аннотации к их типам. Т.е. в приведенном выше примере декларация x выглядела бы вот так: "def x: @ml(1) Tree" (само собой, компилятор вполне способен самостоятельно вывести и @ml и 1, поэтому явное указание аннотации здесь только для примера). Тогда функцию Code.splice мы могли бы объявить как "splice[A](tree: @ml(0) Code[A]): @ml(1) A" и все как бы чотко, но снова возникают проблемы.

Во-первых, метауровней не два и не три, а бесконечное число. Лифт, вложенный в лифт, переносит нас на метауровень 2 и так далее, причем вложенные лифты тоже надо тайпчекать, поэтому наша красивая декларация сплайса ломается и превращается в монстрилу вида "splice[A](tree: @ml(N) Code[A]): @ml(M) A where N < M and M = currentml" (синтаксис исключительно гипотетический).

Во-вторых, снова возникает концепция протекания информации о типах типов через всю программу. Скажем, если мы складываем два @ml(0)-числа, то у нас должно получится @ml(0)-число. А вот если хотя бы одно из этих чисел - @ml(1), то тогда получается @ml(1). Опять же вопрос - есть ли для этого формализация? Реквестирую nponeccop.
glider

емакс, часть 4: ретроспектива

емакс, часть 1: первый взгляд
емакс, часть 2: восторг
емакс, часть 3: windows
емакс, часть 4: ретроспектива

Вдохновленный сегодняшним выступлением @alexott на митапе scala.by, я тоже решил поделиться наблюдениями из своего опыта. Экспы у меня не то чтобы много, но постараюсь быть максимально адекватным. Если я чего-то не догоняю, это не со зла - вы меня поправьте, ладно?

1) Емакс действительно крут. Главные его плюсы, на мой взгляд - неинтрузивность, программируемость и естественная интеграция с консолью. Например, недавно я соорудил наколенную билд-систему, с помощью которой застримлайнил свою работу над абсолютно разнородными проектами в универе. Она прекрасно заинтегрировалась в фар, и не менее замечательно - в емакс. Чтобы из емакса запустить какой-нибудь процесс и вбросить аутпут в буфер, нужны буквально пару телодвижений. Повесить на это все хоткеи и сделать гиперлинки на ошибки - еще немного работы. Пару обтачиваний и вуаля: myke-backend.el. Страшно представить, как что-то похожее сделать в Эклипсе.

2) Практически все можно пилить самому. Это прекрасно и очень вдохновляет (например, одним телодвижением можно посмотреть, на какой именно код забинджен тот или иной ключик), но есть и обратная сторона. Практически все придется допиливать самому. Даже банальную ширину таба нужно настраивать секретным образом (см. отдельную настройку для tab-stop-list), что уж говорить про такие вещи как копипасту, анду или прокрутку (кстати, у меня до сих пор через раз работает выделение мышкой). Это не то что бы уж очень плохо, но надо иметь ввиду, что первые пару недель емакс будет отнимать колоссальное количество времени.

3) Лисп не античеловечный, но и не простой в освоении. Довольно быстро я научился колбасить говнокод (что, наверняка, уже увидели уважаемые гуру емакса, пробежавшись по моему конфигу), но что-либо сложное я предпочитаю писать на чем-нибудь другом. Например, билд-система, упоминавшаяся выше, естественным образом выросла из ад-хок сниппетов на елиспе, но попытки превратить ее в что-то более-менее стройное успехом не увенчались, поэтому я по-быструхе переписал все с нуля на сишарпе. Наверняка, проблемы с удобством стандартной библиотеки и структур данных - всего лишь следствие моего несистемного подхода к изучению елиспа, но что вижу, то и пою. В любом случае, крайне помог бложек Стива Йегги, например, вот этот пост: Emergency Elisp.

4) Емакс - не панацея, что бы не писали в инете (по крайней мере для меня). Для разработки компилятора Скалы я юзаю Эклипс (контрол + клик на дефинишен и дебаг слишком важны, чтобы от них отказываться), для коммитов и истории я юзаю TortoiseGit (magit работает через раз + для чего-то нетривиального в VCS тупо нужен гуй). Вначале я думал, что это я такой нехардкорный, а потом увидел, что все в команде делают то же самое (только гуй к гиту другой, ибо никто не сидит на венде). Даже Мартин, который юзает емакс уже лет двадцать.

5) И все же я очень доволен емаксом. За денек я интегрировал в него греп по проектам с персональными свистелками, после чего выкинул поиск эклипса. Для сложных сессий репла Скалы я тоже юзаю емакс (идея консоли в буфере просто прелестна!). Да и домашки по алгоритмам в латеке я тоже фигачу в емаксе, ибо там подсветка синтаксиса и вручную прикрученный side-by-side превью.

Вот так и живем. Браузинг кода и дебаг в эклипсе, компиляция в фаре, текстовый поиск и реплы в емаксе. Use the right tools for the right job. Искренне ваш, кэп.
glider

Выступление на митапе scala.by

Очень душевно пообщались сегодня на встрече коммьюнити scala.by. С самого начала презентации начался оживленный дискашен, причем временами мы залезали в такие детали, которые даже не затрагивались на митингах скала-тима!

Слайды смотрим и обсуждаем в предыдущем посте: http://xeno-by.livejournal.com/62416.html. Скринкаст будет через пару дней, об этом напишу отдельно. Кстати, слайды с гитхаба и скринкаст коррелируют достаточно слабо, ибо часто дискашен дерейлился в натуральные дебри, поэтому, может быть, кому-то будет интересно посмотреть именно скринкаст.

Вася, спасибо большое за организацию ивента! Ребята, было очень приятно с вами познакомиться и поболтать! С нетерпением жду нашей следующей встречи =)
glider

убунта, часть 5: обратно на винду

часть 1: первый взгляд
часть 2: установка
часть 3: софт
часть 4: интероп с виндой
часть 5: обратно на винду

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

Вначале я стал юзать винду в универе, потом поставил ее в дефолтную загрузку в грубе, а потом и полностью на нее вернулся. Сразу перестал отваливаться wi-fi, ноут перестал зависать после слипа/хибернейта, снова работают hd-сериальчики, больше не греется ноут и время жизни увеличилось раза в полтора (думаю, последние два обстоятельства неким образом связаны друг с другом). Наконец, исчезли мои любимчики - паники с диагнозом "XXX is tainted", которые лечились только ребутом. Эти няшки особенно приятно было ловить во время ребилдов scalac, которые занимают по 10-15 минут.

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

Позитивный опыт

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

Кроме того, я смог оценить ноушен текста как универсального медиума для общения между программами. Отсюда вытекает и консоль-френдлинесс программ, и kiss в плане форматов общения, и много еще чего из unix way. Некоторые утверждают, что это все не специально получилось, а просто из-за того, что юникс был убог. Из-за этого для него приходилось применять самые дубовые подходы, поэтому имеем, что имеем. Хз как оно было, но дубовость это не обязательно плохо (как, например, ООП в перле). Навряд ли я бы понял эту мысль, если бы не поюзал линукс.

Из чисто юзерского экспириенса с линухой вынес пару положительных моментов. Во-первых, концепцию хоум-директории. Будучи травмированным детским опытом с documents and settings, я и не представлял насколько полезно организовать единую свалку файлов (скажем, в c:\users\%username%) и не загоняться насчет того, что лежит на каком диске. Действительно, упрощает мыслительный процесс + никто не запрещает в хомяке хранить не сами файлы/папки, а только симлинки на них. Во-вторых, теперь я знаю, как решать проблемы с разбивкой и бэкапом дисков. В честь этого live cd убунты уверенно обосновалась на скрытом от винды партишене моей флешки. Это действительно очень круто после партишен мэджиков и акронисов.

Несбывшиеся ожидания

Я очень сильно надеялся, что на меня снизойдет просветление, и я раз и навсегда откажусь от гуевых приложений, файловых менеджеров и прочей хрени, и буду работать только из-под консоли и консольного емакса, а также слушать радио "Радонеж". Этого нихрена не произошло. Мне по-прежнему удобнее: 1) упорядочивать большие коммиты специализированными не-консольными тулами, 2) вести несколько проектов при помощи файлового менеджера, 3) юзать эверноут в качестве тула для заметок. Я видел то, чем люди это заменяют, и очень не впечатлен продуктивностью альтернативных методик. Если я неправ, поправьте, пожалуйста. Вон ребе меня убедил в том, что тотал надо выбросить, поэтому я еще не конченный человек.

Да, я раньше недооценивал удобство подхода в стиле "нахерачим все в одну папку - скала-файлы, класс-файлы, скрипты - зато можно будет просто сделать cd и все будет под рукой". Это действительно удобно для одноразовых предприятий, но в перспективе такой подход просто генерит файлопомойку, в которой потом даже самому не разобраться. Я бы очень хотел узнать, как этого не допустить без файлового менеджера. Только не говорите, что надо ручками делать cp/mv и регулярно посматривать ls, чтобы убедиться, что все идет правильно. Просветите, пожалуйста, а то в голове не укладывается.

Как там, на гражданке? Бабы есть?

Ессно, на винде далеко не все безоблачно. Что лично меня рубит после линукса - тормоза емакса, тупейший терминал, отсутствие пакетного менеджера для софта и постоянные выскакивалки из трея. В принципе, для счастья надо только решить #1 (очень больной вопрос, ибо я на емаксе сижу только второй месяц от силы, а жизни без него больше не представляю). Второе до некоторой степени фиксится фаром, а остальное можно потерпеть. В сравнении с тем, через что пришлось пройти на убунте, это вообще детский сад.

Еще вот когда-то меня стращали тем, что под винду нету кучи полезного линуксового софта, поэтому я был очень удивлен, увидев то, что и перл, и латек, и хаскелл - все есть, причем в отличнейшем виде. Да, мейки на винде это гарантированный секс, но я ж не занимаюсь этим каждый день на платной основе. В приятные открытия я отнесу и то, что при особом желании в винде почти все можно сделать из консоли - и в реестре поковыряться, и файловые ассоциации добавить, и информацию о системе получить. Даже MSI файлы и те можно проинсталлировать без next-next-next. Ну да, способ реализации некоторых из этих возможностей, гм, на любителя - это тоже надо признать.
glider

под виндой тормозит емакс. что делать?

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

Проблема в глобальной тормознутости. Например, я тупо не могу зажать кнопку вниз без того, чтобы после где-то десятой или двадцатой строчки емакс не подвис. Понятно, что во всем виноваты аддончики, но ума не приложу, как это запрофайлить - все, что я нашел в гугле для профайлинга, работает в стиле "time <some function>" и только для лиспового кода, а что-то мне подсказывает, что собака порылась не в лисповой обвязке, ибо под линуксом все работает гораздо быстрее. Эту гипотезу отчасти подтверждает, что даже emacs --no-init-file подтормаживает, хоть и едва-едва заметно.

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

А, да, емакс у меня версии 23.2, скомпилированный под венду (под линуксом 23.1, ибо я ставил из репозитория убунты). Временами я юзаю цигвиновские пути (которые резолвятся емаксовским аддоном), но тесты я проводил на безфайловых буферах, поэтому цигвин тут ни при чем, наверное.

upd. Проблема решилась: http://xeno-by.livejournal.com/59566.html. Пришлось поменять рендерер фонтов, выбросить ECB, ибо у него под капотом сидит жрущий CEDET, а также отключить linum.
glider

github: как в форкнутом репозитории смержиться с апстримом

Я подозревал, что такое возможно, а сегодня, как понадобилось - научился:
* http://help.github.com/fork-a-repo/
* http://stackoverflow.com/questions/849308/pull-push-from-multiple-remote-locations

Заодно догнал, зачем нужно магическое заклинание "git remote add origin git://github.com/username/newproject" для того, чтобы инициализировать только что созданный проект на гитхабе. В принципе, логично, хотя в меркуриале было совсем по-другому.
glider

макросы: обзор литературы

Зачел сегодня две фундаментальные работы по макросам в Немерле: "Syntax-Extending and Type-Reflecting Macros in an Object-Oriented Language" (далее "диссер") и "Язык Немерле, часть 5" (далее "статья"), а также за эти несколько дней поговорил с Владом Чистяковым (спасибо большое, Влад, за желание помочь и детальные объяснения!). Несколько промежуточных выводов:

1) Квазицитирование крайне изящно. Всего три прозрачные языковые конструкции (цитирование, антицитирование и сплайсинг, см. раздел 8.3 диссера, если покороче, или раздел "Квази-цитирование" статьи, если развернуто) раз эдак в сто упрощают парсинг и генерацию AST. Особенно впечатлило использование антицитат и сплайсов в паттерн-матчинге. Внутренняя красота квазицитирования особенно остро воспринимается после мучений с композируемостью линка.

2) Впрочем одна знакомая до боли проблема остается. Как лифтить (т.е. преобразовывать в AST) код из внешнего мира? Адептам стейджинга в этом плане просто (кстати, рекомендую презентацию по ссылке, первая работа Олега, которую я понял) - все функции и значения, имеющие стейджнутый тип, они лифтят (явным образом в стиле tagful или неявно через tagless - что это значит см. линк или спрашивайте у меня), а остальное игнорируют. Достигается это ценой синтаксического оверхеда на типизацию + возможными издержками на tagful представление кода (см. сюда за подробностями), но зато ведь достигается. А с макросами сложнее - в большинстве случаев без явного антицитирования они даже не пошевелятся что-то залифтить, да и, самое главное, код, скомпилированный без лифтинга, (например, внешние библиотеки) уже никогда не сможет быть залифченным. Также появляется неочевидная дилемма на тему того, разрешать ли макросам видеть значения в лексическом скоупе (см. раздел 2.3.3 диссера).

3) Также совершенно непонятно как сделать ортогональной кодогенерацию на макросах в статически типизированном ОО-языке. Во-первых, скорее всего придется выносить макросы в отдельный юнит компиляции. Во-вторых, появляется дилемма: юзать макросы до типизации и иметь возможность нагенерировать новые типы, или юзать типизированные AST, но мириться с залоченным пространством типов (лучше даже не думать, что будет, если сюда добавить тайп-инференс). В-третьих, объектность подливает масла в огонь в плане того, что появляются классы (концептуально новая сущность, которая не композируется с функциями) и наследование. В итоге получается кошмар стейтфул программирования, когда в зависимости от фазы луны операции над данными то разрешены, то запрещены. Неудивительно, что создатели F# попросту скипнули кодогенерацию, а реализовали только read-only квазицитаты.

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

5) Кроме того для языка с синтаксисом макросам желательно иметь контроль над парсером (см. слинкованные креативы про Немерле, а также технический репорт "Genuine, Full-power, Hygienic Macro System for a Language with Syntax"). В таком случае можно реализовывать полезные вещи вроде добавления своих атрибутов к декларациям (типа async method или method precondition) или введения кастомного синтаксиса. upd. Вообще-то, без этого можно жить: первое решается при помощи аннотаций, которые будут запускать соответствующий макрос, некоторое подмножество второй фичи уже есть в скале (например, см. каноничную реализацию цикла while).

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