November 21st, 2016

Book

HNC, Windows, SublimeHaskell и stack

Глобальная претензия к SublimeHaskell всего одна - https://github.com/nponeccop/HNC не поддерживается, т.к. кастом билд использует новые фичи кабала 1.24 (setup-depends), которые не поддерживаются стеком, из-за чего не получается собрать HNC стеком, а сборку кабалом мне было лень сетапить под виндой. Претензию выставлять в гитхабе нет смысла поскольку это баг стека, который уже есть в трекере стека, а под кабалом может оно и заработает. Штатно я (и тревис) собираем HNC кабалом под линуксом, но там из-за бага в ядре нет иксов под используемым мной нестандартным гипервизором.

Иксы есть но нет мыши, и этот баг репортить нет смысла, поскольку ядро без мыши старое, а в новом ядре нет не то что мыши - нет загрузочного диска. Но только под арчем, а арчеводы не умеют в Hyper-V, а я не умею в диагностику ядра. Т.е. поставить саблайм в линукс и проверить там для меня относительный геморрой.

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

Тестил только https://github.com/nponeccop/HNC/blob/master/HNC.hs#L41-L60

Чего хочется, находясь в теле ff (что я попробовал, и не получилось):

- комплита локальных идентификаторов, пусть даже текстового - dump должен предлагать dumpOptFlag и dumpGraphFlag
- комплита qualified imports - M. должно предлагать комплит экспортов из Data.Map
- правильной подсветки guards (этот баг есть в трекере саблайма). Причем лично для меня безглючность подсветки важнее фичастости - т.е. лучше некоторые сущности отдельным цветом не выделять вообще, чем выделять их каждый раз разным цветом.

Что я не попробовал, но попробую, как только начнет собираться:

- https://github.com/nponeccop/HNC/blob/master/Test/Main.hs должен видеть QuickCheck и HUnit (это часто не поддерживается, поскольку Test.Main считается принадлежащим другому таргету в SPL.cabal где quickcheck не указан в build-depends)

- https://github.com/nponeccop/HNC/blob/master/CPP/CompileTools.hs должен видеть Bar (это как правило не поддерживается, потому что о местонахождении Bar знает только плагин uuagc-cabal, который говорит это Кабалу. Т.е. если вместо спрашивания у кабала пытаться угадать - будет хуй. Высший пилотаж там же - это догадаться, что файлов Bar.hs у меня минимум два (разные файлы в разных таргетах) и соответственно предлагать 2 места при go to definition у AG.compile2

- https://github.com/nponeccop/HNC/blob/master/HN/MilnerTools.hs - на нём любили падать все, уж не припомню почему
Book

Haskell actively rewards worst practices and punishes best practices!

По материалам Габриэля нашего Гонзалеса.

1) Poor performance

The path of least resistance is to use linked lists and strings instead of text and vector. This problem is so pervasive that I see even respected and experienced library authors who care a lot about performance succumb to the convenience of these less efficient types every once in a while.

2) Excessive abstraction

As you learn the language you begin to realize that Haskell makes some types of advanced abstraction very syntactically cheap and some people get carried away. The language fosters and encourages "architecture astronauts". The temptation to play with all of Haskell's abstract facilities is so strong for some because for those people abstraction is too fun!

3) Unchecked exceptions

A lot of people mistakenly use error instead of throwError without realizing the consequences of doing so. I've seen otherwise very smart and talented Haskell programmers get this wrong.

error is the worst way to throw a Haskell exception because it is:
- marked pure, so it can strike anywhere
- asynchronous, so it can strike at any time
- completely invisible at the type level
- triggered by accidental evaluation
Book

HNC - Этап Кодогенератора

Задачей было из Милнеровского лет-полиморфного ЛИ получить C++ путём буквального кодирования замыканий классами, функций - boost::function, а полиморфизма - шаблонами. Ну, и чтоб работало совместно с вызовом деструкторов при выходе из блока, и рушилось в рантайме при фунаргах.

AST бралось из быстро написанного на Парсеке парсера и аннотировалось типами с помощью чекера inv2004. Притти-принтинг С++ как таковой тоже не составлял трудностей, основная трудность - в классификации идентификаторов из ЛИ в один из 13 подвидов, которые в С++ выглядят по-разному.

Вот первые 5 из 13 способов которыми может транслироваться милнеровская аппликация a и x в зависимости от относительного "дебрюйновского" положения a и x и кучи других факторов:
data CppQualifier
	= CppAtomVar			-- a(x), x(a)
	| CppContextVar			-- a(ctx.x), ctx.x(a)
	| CppContextMethod		-- a(hn::bind(ctx, &local::a), ctx.x(a)
	| CppFqConst String		-- a(aaa::bbb::x)
	| CppFqMethod String		-- a(&aaa::bbb::x), aaa::bbb::x(a)
        | ...
При этом 13 это не все случаи, поскольку я не допилил и есть падающие тесты.

В процессе написания выяснилось, что как не пиши классификатор - выходит атрибутная грамматика. Поискал грамматики на хакадже, нашёл какую-то недоделанную на тот момент на тайп-фу, плюнул и нашёл Utrecht University Attribute Grammar Compiler, который кондовый препроцессор в духе Happy безо всякого тайп-фу, только вместо генерации AST генерит функцию из наследуемых атрибутов в синтезированные https://wiki.haskell.org/The_Monad.Reader/Issue4/Why_Attribute_Grammars_Matter , которая у меня и так была.

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

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

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

Да и даже если б я пробился - всё равно столь чудовищные монстры меня не устраивали, и я решил, что пора браться за оптимизатор.