Recent Entries

You are viewing the most recent 50 entries.

16th November 2014

01:01: Interstellar
Until now, I always answered any questions about this movie with short remarks. Like "don't waste your time", or something like that. But now I have some free time, so I figured, why not try and review it properly? If anything, Nolan deserves to be taken seriously. When Coen brothers make something terrible, you just shrug and say "well, that's Coen brothers, it's what they do". But Nolan, let me remind you, created such masterpieces as "Inception" and "Memento", and "Batman begins" was pretty good too.

Just a warning. I'm going to put some spoilers here. Big ones. I'm not writing for the newspaper; I'm writing to my personal blog. So, you've been warned.

So, "Interstellar". Let's see what we've got.

1) Plot. A good plot seemed to be the greatest virtue of Nolan films so far. And it's very hard to make a good movie without a good plot. There are examples of that, like Bergman's "Smultronstället" ("Wild Strawberries"), but only a few of them. Even geniuses like Bergman do not succeed every time they attempt something like this.

And the plot here is really bad. Let me give you a few examples.

The characters are looking for a new home for Earth population. A while ago a few people were sent to different planets (only one astronaut per planet) and three of them sent back a confirmation that the planet is good and can serve it's purpose. Due to the lack of fuel, our heroes must choose which of those planets to visit, and they eventually choose one that was studied by the leader of the previous mission, Dr. Mann. He is still on the planet, and, after landing there, they'll take him back to Earth.

From that description it should be completely obvious to you (even if you didn't see the movie) that Dr. Mann is a liar who just (correctly) guessed that otherwise he won't be rescued. And that's exactly what happens here. The situation could be saved if Dr. Mann just admitted his lie and begged the main characters to forgive him. But no. Mann, unable to hide the fact that the planet can't be the new home of humanity, tries to kill everyone and get back to Earth alone on their spaceship. I don't know what could be more hackneyed than that. And, of course, he fails.

Another example. Why the Earth population even needs the new home? Because edible plants on Earth slowly die. It seems that there are two reasons for that: thick dust that somehow flows through the air and covers everything, and some pathogen. Yeah. So, instead of fixing the problem on Earth, they decide to just pick a completely different planet and try to make it habitable. Does it really seem easier? Well... not to me.

Or the use of aliens here. Aliens don't appear on screen (thankfully), but it seems that they created the wormhole in the Solar system, that allows humans to reach other planets. Throughout the movie, there is more evidence that aliens are, in fact, quite fond of humanity and did that specifically to facilitate humans' escape.

That much I can buy. There are additional questions — like, why didn't they create their wormhole closer to Earth, so that it would be easier to reach — but that's more or less OK. But later characters of the movie make two statements. First, aliens are "five-dimensional" creatures, they don't understand the concept of time, and, therefore, they need humans to do most of the job. And, secondly, aliens are really humans from the future, just very advanced.

You do see the problem here, right? Like, these two statements are in direct contradiction? What's more, neither of them is substantiated by the evidence, it's completely unclear how the main characters figured this out.

2) Acting. Not much to say here. Nolan, as usual, doesn't give the actors much to work with. While that worked with aforementioned "Inception" and was a bliss with "Memento", whose lead actor was just unable to act, here it doesn't work. Because of the difficulties with the plot. And Mr. McConaughey, who plays the main character here, isn't a good enough actor to overcome the limitations. In fact, as former space pilot turned farmer, who returns to being space pilot, he seems more interested, more alive, when he works on a farm, than when he flies the ship through space. And that contradicts his repeated statements that he hates the farm and was born to fly.

3) Scientific background. That was another thing that was well handled in, say, "Inception". Of course, the premise of "going into the mind of a sleeping person" was completely fantastical, but at least some consequences were well tied to the real world — like gravity. When the characters are sleeping in a van, and that van falls freely, there is no gravity in their dreams.

"Interstellar" instead sells itself as a "hard sci-fi", which follows the laws of physics as close as possible. OK, let me just give you an example.

"Hey, let's send a probe to the black hole, so that it would send back information about what's inside".

I kid you not.

And then they do exactly that. And a human — the main character — goes in along with the probe. What tidal forces?

At least this astronaut, as well as the robot doubling as a probe, didn't manage to send a signal outside. That's good. Why did he ever thought he would be able to do so is incomprehensible. I guess he was really stupid. But then there comes the part where he encounters a strange place inside a black hole that lets him communicate with his daughter who is still on Earth, sending all the collected data about black hole to her. In Morse code. Erm... isn't ASCII better for that? And, I don't know how much data he was sending, but I'm pretty certain that it was several megabytes at least. So... how long did his daughter stay there, writing down his messages? Months?

Anyway. If you want hard sci-fi, read "Martian" by Andy Weir, and do not watch this.

Was there anything good about the movie? Yes. But only one thing. Robots. Robots were helping people. Not one of them went on a murderous rampage due to some technical problems. And I especially liked the fact the were not made humanoid without any reason; instead, they generally were just big black boxes. Some thought was obviously given to their design, which made their movements (sometimes very fast) quite believable.

But that is not enough for a 3-hours movie. And, not to end this review on a positive note, here is, again, something regarding the plot.

I'm OK when an astronaut who landed in water says "Damn, our engines are wet, so, let's pump some oxigen into them; that way we would be able to make the fuel burn". I don't know if it's something that could work in reality, but at least it seems believable on screen. But, instead, we get this: "Damn, our engines are wet; we have to wait for an hour until they dry out, despite the fact that every second counts now. <skip almost an hour> Oh, there is a huge wave coming to us, and we need a few minutes more; let's pump some oxigen into the engines; that way we would be able to make the fuel burn". Erm... why didn't you do the same thing an hour ago? Or a minute ago, for that matter?

Bad movie. Bad Nolan. No cookie for him.

9th October 2014

18:05: When existentials aren't enough
> {-# LANGUAGE GADTs #-}
> {-# LANGUAGE RankNTypes #-}
> module Exists where
I've discovered a certain trick that seems to recur in my code. It might be a sign of me having too much time on my hands, which is commonly referred to as "perfectionism". Anyway, I thought I'd share it with the class. And forgive me if my exposition is overly generic; I do have real examples, but there is some extra stuff that obscures the general idea, which is what I want to present here.

Let's start with the simple example. Suppose we have some input, and want to generate some output from it (remember, I've told you it would be generic). Such "generator" is just a function of type
> type Gen1 m input output = input -> m output
Note that generation is done inside some arbitrary monad, so as to allow side effects.

How do we use such a function? Well, that's very simple, we just apply it and use it's result:
do output <- gen1 input
   process output
That's certainly good, but imagine that this generation has something existential about it. The output we generate has an additional argument — sometimes it would be a phony type intended to be a "marker" of this specific output (which is the case in my real-life code); sometimes it would read the type from external sources, etc.

Well, that's not a problem at all; existential types (superseded by GADTs) serve exactly that purpose. So, in this case we use an existential type
> data Exists output where Exists :: output phony -> Exists output
Then the generator would have a slightly different type
> type Gen2 m input output = input -> m (Exists output)
Using such a generator is almost as easy as the first one:
do e <- gen2 input
   case e of Exists output -> process output
In fact, we can easily convert the generator of the second type to the generator of the first type. The only thing we'd have to care about is adding this extra "phony" type to the output. We can do it like this:
> newtype WithPhony output phony = WithPhony output
Now, the actual conversion is done like this:
> withPhony :: Monad m => Gen2 m input (WithPhony output) -> Gen1 m input output
> withPhony gen2 = \input -> do {Exists (WithPhony output) <- gen2 input; return output}

Here comes the trick I've been talking about earlier. Assume that our generator is somewhat recursive, so that it's input depends on the output. What's worse, we need it to have this extra type as well. So the situation seems freaky: we have all the essential parts of input, then we need to generate output AND find out the "phony" type, so that we can amend our input. That's not usually a problem when there are no extra types; but with them in place things become interesting.

Let me give a (kinda real) example. Assume that you're creating a couple of tables in a database. You want to mark them with phony types, so that indices for one table are not accidentally used with another. Normally that would be like a situation described above, with existential types; but now you also want those two tables to reference one another. That mean that the specification (something like CREATE TABLE command) for each of them contains the phony type that marks another one. So we can't know the phony types beforehand; we can't define them externally, because then it would be possible to create two different table with the same marker type; and we need them as part of our input. Tricky.

So, returning to the general question, we have some function of type
> type ProduceInput m part input phony = part phony -> m (input phony)
Note that we don't use the full output; type safety aside, it's quite possible that we can't pass the full output "back in time", only the part of it.

Let's ask ourselves a question: suppose that we have the "generator" that produces our output, and it's type correct. When we use it — what would we have other than the generator itself?

Instead of input we would now have the function that produces the input from the part of output. Is that all?

No. We would also have the processing function, which takes the output and produces some result. It was present in the examples above, but it was not treated as part of the equation. But there is no reason why it shouldn't. And what's more exciting is that we don't really care about the extra types; we only care about the final outcome. So, we have this data:
> data Gen3Input m part input output phony result =
>     Gen3Input (part phony -> m (input phony)) (output phony -> m result)
And that's exactly what we need. Now our generator can be typed as this:
> type Gen3 m part input output =
>     forall result. (forall phony. Gen3Input m part input output phony result) -> m result
Using this generator is straightforward; in fact, it's even easier than using first two versions:
gen3 $ Gen3Input generateInput process
Writing this kind of generators is more challenging, but only because it does a more complicated job. Essentially the process is outlined above: we produce our input using the part of the output, not yet known; in the lazy world of Haskell this is completely normal, it's just that the input won't be generated fully until the next step. Then we compute the output from the input, using whatever techniques we need, and feed the required part of it back to the input producer.

For example, in case of two tables referencing each other, the only "part" we need is the markers themselves; so, this "part" would actually contain zero bits of real information. Therefore we can have our "input" (the specifications of tables) in full, and create tables from it.

We can, as before, convert this generator to the previous one. The part of the output we feed back would be void here.
> data Void phony = Void
We also add extra phony type parameter to input. The conversion itself is quite simple.
> withDep :: Monad m => Gen3 m Void (WithPhony input) output -> Gen2 m input output
> withDep gen3 = \input -> gen3 $ Gen3Input (\Void -> return (WithPhony input)) (return . Exists)
Note that here we don't use the full continuation as our processing function; we only need to advance it a bit farther than extra type goes. The existential type constructor gets rid of it, so we can stop there.

Well, class, that's it for today.

15th September 2014

15:13: Oldschooling
It's XXI century. We have flying cars now. What we also have, is a lot of research in programming languages. We have heavy books on refactoring. We have tons of "best practices". And then...

You know, a while ago I bitched about generics in Rust not being really generics, but rather templates, as they are specialized for every type they are used with. In fact, they are more limited than templates, as they don't allow partial specialization.

A few days ago I got wind that they finally woke up and implemented generics as, well, generics. I've checked immediately, and, no, we are still at the same spot.

But then another thought came: how can they specialize generic functions for types they know nothing about? I mean, if module A defines a generic function, and module B uses it with the type also defined in B, and A is compiled first — there is no possible way to specialize this function for the type defined in B, right? C++ avoids this by having all templates implemented in header files, so that they are available when compiling B — which really means that the function is NOT compiled with A (unless it uses it with some other type), but rather with B. Rust can't do that, after compiling the module you can safely remove the source code, and it will work fine.

And somebody answered my question with this: http://www.reddit.com/r/rust/comments/2c6pn0/how_does_rust_implement_calling_generic_functions/cjcio0p

Yep. They keep the source code in the compiled file.

Well, not EXACTLY the source code — the AST. But the difference is, in my book, négligeable.

Yeah. It's THAT bad.

On the other hand, there is Go — which is another new language, intended to fill the same niche as Rust — or at least a close one. It solves the problem with generics elegantly and efficiently — by not having generics. At all.

Which is fine, if there were hope that generics would emerge in some later version — like it was with Java. But it seems that Go people rather enjoy not having generics: "Lack of generics has bothered me a little, but copy and paste with a multiple-cursor editor really makes short work of it."

Yes, its XXI century, and the earth is doomed.

12th September 2014

15:52: Swifting
You know, I've tried Swift again, with the latest beta available, and it kinda works.

Still seems like something inside it is crashing every other second, but XCode holds and playground... playgrounds.

I even tried my generics test, and was able to make it work. So it seems that Swift has real generics (unlike Rust). Nice.

10th September 2014

22:55: Time wasting
Yesterday's Apple Keynote turned up to be a disappointment for me. There were four topics there — and all of them were not for me.

1) iPhone 6(+). I am a bit hesitant at this matter — I have yet to see the actual device, let alone feel it in my hand, but for now the seem too big. I don't mind big things — I carry an iPad with me almost everywhere — but this is the phone. I like my iPhone 4s, and even iPhone 5 seems a bit too big. And the one-handed mode? Looks like a dirty hack, which is not what I would expect from Apple.

2) Apple Watch. Well, I don't like watches. I don't like something on my wrist. Never did. At school, I was wearing a watch on a chain for some time. Now, I don't wear watches at all. I always have a phone with me, and it shows the time perfectly well.

Also, the Apple Watch home screen looks ugly.

3) Apply Pay. It's really great. But only if you have iPhone 6(+). So — not for me.

4) Music. Well, that was always the crappy part of Apple events. Nothing new here.

So. I might revert my judgement on iPhone 6 (and even Plus) if, upon closer examination, it would prove to be not so bulky as it looks. If that happens, Apple Pay might eventually become useful for me too (although it only works in US for now, and my chance of moving there is pretty slim). So, there is hope for me and Apple — but not much of it.

30th August 2014

20:16: Hating
There is a bunch of actors, who, by starring in the movie, ruin the movie completely.

By "starring" here I mean "playing somewhat significant part". Cameos usually don't hurt much — with a few exceptions.

By "ruin the movie" I mean "make the movie unbearable for me to watch". As my opinion is clearly superior to everyone else's, that is all that counts.

Here's the list, which I'll probably amend later:

Konstantin Khabenskiy
Johnny Depp
Bill Murray
Robin Williams
Adam Sandler
Jim Carrey
Steve Martin

Only Khabenskiy ruins everything he touches.

Amazingly, not a single female actor have made this list. I don't know what that means — either my tolerance to actresses is much bigger, or it's easier for the shitty male actor to become a big star than for a female one.

4th July 2014

14:09: Customizing
I hate customizability.

Don't get me wrong. I'm not saying having an "Options" window hidden somewhere is wrong. Quite the contrary. Only the smallest programs can work without it. Or the programs that are nothing but a big "Options" window (like, "System Preferences" in Mac OS X).

And the idea of enabling the user to change anything and everything, tweaking the program and setting every little detail so that it's just right, sounds very exciting. Kinda like communism — I mean, come on, who doesn't want to get whatever he needs, while giving back only as much as he can, right? And, like communism, it doesn't work. Or, if implemented (which, unfortunately, requires somewhat less efforts than establishing communism), it leads to macabre, to say the least.

The problem as I see it is that the resources are limited. They are always limited. And at some point the decision has to be made: either we figure out the best way to do something, and proceed accordingly, or we insert enough hooks so that the user can do it himself. It requires a lot of effort to do either of this things, but doing both at the same time is an order of magnitude more complicated. We don't just have to make things look and work good; we have to make sure that if the user changes something so that it no longer works as we imagined, the rest remains intact.

So, nobody goes both ways. Either we get the thing that just works — and if it doesn't work as we want, our only option is to discard it and get something else — or we get a piece of shit; a customizable piece of shit, but still.

I really prefer the first option. I'm really flexible; I don't mind going from Mac OS X at home to Windows 7 at work to Debian Linux in VM. What I don't want is to spend my time configuring tools so that they at least do their job. I don't want HammerFactory; I just want a really good hammer, and if the one I've bought doesn't suit me, I'll buy another.

What is really sad is that sometimes the first option just isn't available. There are some good IDEs out there (the best I've ever seen is probably Visual Studio — yes, seriously), but there is nothing that works for Haskell better than Emacs. And Emacs is a terrible IDE. Yes, you can customize it. No, you can't make it good. And when you find out you can't — well, they would laugh at you, call you names and say that it's all possible, you just haven't tried hard enough. Which is kinda true — but that's the point. I want to be an awesome Haskell programmer; I don't want to be an awesome Emacs developer. Why? Because I don't.

I'm not attacking open source, by the way. A couple of days ago I've had a "training" in the thing called "Rally". It's supposed to be a collaboration tool. Very enterprise-y. And yes — quite customizable. No, it doesn't work; but nobody cares. And yes, we are stuck with it. Management decision.

On the other hand, we have open source tools like "git", for example. Do you customize it a lot? I bet you don't. Yes, there are some customization parameters, like "user.name" (which git explicitly asks you to set), and there are ".gitignore" files — but those are minor things. Git just works, and works great.

So, customizability isn't a good thing. It's just an excuse for developers to make the user do their job, while ridiculing the user for failing.

19th June 2014

11:10: Switching
First, the link:


If, by any chance, you don't read Russian, here is the essence of it: Russian parliament proposed taxation of using foreign words and expressions (what does that even mean? how on Earth the expression can be foreign without foreign words in it?) in public statements, if such statements are made using the official language of Russia (did they forget what language is official in Russia? or they intend to change it?).

As blogs are now considered public media, and I certainly don't want to violate that law, I think I'll switch to English from now on, so as to not make any public statements in Russian. I might consider switching back if they change the "official language" to something else.

7th June 2014

22:40: Стрижиное
Ну что, попробовал я таки этот Swift. Скачал бету XCode, распаковал, запустил. И доложу я вам: это штука с огроменным потенциалом. В смысле, ни фига не работает.

Я, честно сказать, думал проверить ихние дженерики своим любимым тестом, который C++ не прошёл, а, скажем, Java — вполне. Наивный.

Дело в том, что когда вы пишете код в XCode, то вам показывают места ошибок. Это очень удобно. Однако делается это путём запуска компилятора в фоне. А компилятор сей страдает падучей. И когда он сегфолтится — а это происходит довольно часто — весь XCode вылетает нафиг.

Дальше ещё веселее. Вы запускаете XCode заново, он восстанавливает тот же файл, снова прогоняет его через компилятор, тот снова сегфолтится, и XCode снова вылетает.

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

Так что пока ихняя бета (которая beta than nothing) отправляется в корзину. Увы.

21st May 2014

13:55: Врачебное
Вот допустим, позвали меня помочь обуздать MS Word. Или какую-нибудь более специфичную (но распространённую) программку, неожиданно отказавшуюся работать.

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

Это всё - совершеннейшие мелочи, которыми гордиться не стоит. По совести, это не самый лучший способ использования меня. Но он работает.

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

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

6th April 2014

13:33: Пракрым
Выскажусь-ка и я про наболевшую тему.

ИМХО, популярный мем "затокрымнаш" в корне неверен. Правда состоит в том, что Крым в кои-то веки ПЕРЕСТАЛ быть нашим.

Год назад я мог совершенно спокойно съездить в Крым в отпуск. Ну, паспорт был нужен, да, но это невеликая проблема. Виза не требовалась. По-украински я никогда говорить не умел, но проблем из-за этого не испытывал: в любом крымском магазине со мной с удовольствием общались по-русски, да и спросить дорогу я всегда мог на родном языке.

Иначе говоря: Крым был МОИМ.

Сейчас, когда эйфория по поводу высоких пенсий у крымчан проходит (и, вроде, очень быстро проходит), что останется? Кем я там буду? "Оккупанта-империалиста, рашен гоу хоум". Крым перестал быть моим. И не только моим.

Спасибо, как говорится, партии за это.

24th March 2014

16:30: Deque
Наткнулся тут на простенькую задачку: написать стек, поддерживающий, кроме стандартных push и pop, ещё и операцию min, которая возвращает минимальное значение из содержащихся в стеке. При этом все три операции должны выполняться за O(1).

Ну, задачка действительно простая, но меня натолкнула на мысль: а что, если вместо стека делать deque, т.е., массив элементов, к которому можно добавлять новые (и удалять старые) как с левого конца, так и с правого? При этом по-прежнему хочется делать min.

Пока что у меня получилась реализация, делающая pop_front, pop_back и min за O(1), а push_back и push_front - за амортизированное O(1).

Вопрос к коллегам: это где-нибудь есть?

22nd March 2014

15:21: За пятнадцать минут
Тут у ivan_gandhi обнаружилась запись1 примерно такого содержания:

Всем, кому неловко ощущать себя "диванной сотней", которая возмущается в интернете, но не может сделать ничего практического в борьбе с российскими оккупантами. Теперь такая возможность есть. Группа адекватной русской молодежи, не имеющей ничего общего с путиноидным быдлом, начинает кибервойну против путинского режима. Участвовать в ней может любой желающий - достаточно зайти на <ссылка удалена — migmit>, скачать и запустить маленькую программку. Понимаю рефлекторный ужас, вызываемый таким предложением, но НЕТ, это не вирус, программа никуда не устанавливается и не запускается автоматически при перезагрузке компьютера. Она включается ТОЛЬКО руками пользователя. Вы полностью контролируете, когда она работает, а когда - нет. Вы можете в любое время ее включать и выключать.
Программа НЕ меняет никакие файлы на Вашем компьютере, не загружает его память или процессор, и использует только свободную ширину канала Интернет. Другими словами, ее работа никак не повлияет на работу Вашего компьютера. Программа проверена IT-шниками из Правого сектора, которому нет никакого резона дискредитировать себя, агитируя на своем официальном сайте за установку программы, которая могла бы повредить его сторонникам.
Что она делает - ну, вы уже поняли ;) Если нет - читайте по ссылке выше. Атомные реакторы не взрывает и данные не крадет.
Опасно ли, что "за вами придут"? В мире не было прецедентов, чтобы приходили за пользователями, чей компьютер используется для DDoS-атак. Пользователь в таких случаях считается заведомо невиновной стороной, которая знать ничего не знает, да и слишком таких пользователей много.
Кибервойна продолжится до тех пор, пока российские оккупанты не покинут Крым и вообще территорию Украины.
Учитывая возможность блокировок, прошу максимально широко распространять данную инф-цию.

Що мы тут видим. Во-первых, сам факт "скачайте мою программку и запустите" — это уже тревожный звоночек. Необходима дальнейшая работа. Ладно, идём на сайт.

Скачиваем. Версия — только под винду, исходников нет. Ладно, тем лучше — случайно я её точно не запущу. Лежит на depositfiles (почему не на собственном сайте?). Лежит в виде ЗАПАРОЛЕННОГО АРХИВА, с именем "что-то-там_Pass_123.rar". Вы знаете, зачем выкладывать на depositfiles файл, защищённый паролем, включая сам пароль в имя файла? А я знаю. Чтобы антивирус на depositfiles не залез внутрь и не заорал благим матом.

Ладно, скачали, распаковали. Там один exeшник. Открываем его в emacs, и видим строчки "UPX", "UPX1"... Ладно, sudo port install upx +lzma, распаковываем и это. Открываем снова, и видим множество строчек типа "TImageList". Понятно, дельфи.

Дальше смотреть на файл глазами мне надоело. Взял я IDA Pro, загрузил. Смотрю для начала секцию импорта. Интересно, если на сайте написано

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

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

Дальше стало неинтересно. До кучи я загрузил программку на malwr.com. Антивирусы распакованный вариант не тронули, но сайт отрапортовал три вещи: во-первых, программка никакого DDoS-а даже не попыталась сделать, во-вторых, этот VB-скрипт действительно создала (то есть, это не дохлый код), и, в третьих, таки прописалась в автозагрузку.

Вот так вот.


1Перепост был случайным, по-видимому.

3rd February 2014

23:25: Не знаю Emacs и не хочу знать.
Несмотря на то, что пользую его постоянно.

Вот ПОЛНЫЙ список того, чем я реально пользуюсь в Emacs:

1) Базовые вещи, связанные с редактированием текста - открытие, просмотр, набор текста, перемещение курсора, выделение, копирование, вставка, удаление, отмена последнего действия (какой кретин решил, что "C-x u" это удобно???), сохранение. Notepad.exe может всё это и ещё чуть-чуть.

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

3) Одновременная, в рамках одного окна, работа с несколькими файлами. В разных буферах, но в одном окне.

4) Абсолютно базовые вещи, связанные с поддержкой языка программирования. А именно: подсветка синтаксиса и более-менее разумная расстановка отступов. Сюда же: автозамена табуляций на пробелы.

5) Киллер-фича: возможность запускать REPL в том же окне (в другом фрейме). Сюда же: интеграция REPL с редактором, из которой я реально использую C-c C-l, C-c C-t и C-c C-i, причём последние два - довольно редко. Ещё сюда же: возможность использовать окно REPL по существу как то же самое окно редактора - за исключением ввода произвольного текста в произвольном месте (даже C-y работает). Ещё сюда же: грамотная подсветка в REPL.

6) Быстрый переход к месту ошибки. Помогает.

7) Даже как-то стыдно упоминать, но: полноэкранный режим работы, причём графический. У меня макось, и возможность убрать из поля зрения абсолютно всё очень приятна (ладно тулбар, я даже в меню не лазил уже несколько лет как).


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

1) Какие-либо системы управления проектами, системы автоматической сборки и т.п. То есть, я, конечно, пользуюсь ими (например, cabal-ом), но Emacs тут ни при чём, cabal запускается из терминала, либо, в крайнем случае, из того же REPL.

2) Системы контроля версий. Опять-таки, я их пользую (обычно hg), но из того же терминала. Мёржи делаются не в каком-то специальном режиме, а "как есть", в одном файле.

3) Средства удалённой работы. По-моему, редактировать нелокальный файл — некий идиотизм.

4) Сниппеты. У меня не такая хорошая память, и думать о том, на какой аккорд у меня повешен сниппет, я не имею ни малейшего желания.

5) Фолдинг. Вообще не понимаю, нафига он нужен. Если надо одновременно видеть две функции, проще разместить их рядом, а не сворачивать весь код между ними.

6) Теги, которые etags. Наличие :i в REPL позволяет в большинстве случаев получить всю необходимую информацию, вообще не заглядывая в исходник; если таки нужно посмотреть, что там, то в выводе :i сразу видно, в какой файл смотреть.

7) Языкозависимое автодополнение. Типа, я набрал точку после имени модуля, и сразу получил список функций в нём. Если сильно надо, я наберу :bro в REPL. И да, мне не лень ОДИН РАЗ набрать идентификатор типа insertWithKey, а в остальные разы я его получу примитивным автодополнением.

8) Доступ к документации. Для документации у меня открыт браузер, и я быстро найду всё, что нужно. А если я уже знаю функцию, которая мне интересна, то, как правило, кроме её типа мне не нужно ничего, а его я получу из REPL.

9) Работа с файловой системой. У меня есть командная строка, и я умею ею пользоваться.

10) Поиск по многим файлам. Это очень редко нужно, а когда нужно — я знаю grep-фу.

Список можно продолжать бесконечно.

Суммируя: единственное, что РЕАЛЬНО держит меня на Emacs'е — это REPL. Всё остальное, что мне нужно, есть в ЛЮБОЙ IDE и в почти любом редакторе для программистов. Но эта фича — ключевая. И да, Emacs — худший из имеющихся редакторов (кроме, возможно, Vim), если забыть про эту фичу. Но с ней получается, что остальные ещё хуже.

Более-менее приблизился к этому Sublime Text. Но искаропки оно работало, когда я на него смотрел, из рук вон плохо. Достаточно уже того, что подсветка в REPL была а) такая же, как в коде, и б) не отличала код, набранный мной, от результатов, выводимых выполняемой функцией. Вообще, у меня создалось впечатление, что там ещё кучу всего пилить и пилить.

Leksah и Yi у меня собрались только в текстовом режиме. Я люблю терминал, но редактор должен быть отдельно.

Всё. Выдохнул.

Update: OK, убедили, возможно когда-нибудь я стану пускать grep из Emacs.

Update 2: ещё одну полезную штуку вспомнил — htmlize.el, чтобы весь код, вместе с подсветкой, экспортировать в HTML.

23rd January 2014

19:11: Тут по поводу вебдева гонят
Обнаруженные на данный момент гонщики:

Я профессионально вебом не занимаюсь, но чисто для себя - очень даже. Предпочитаю Happstack, писал под Play (на Java!) и даже когда-то управлялся с уродским серверным диалектом жабоскрипта под названием KScript (когда работал в "Кодексе"). Так что вместо прогнозирования попробую заняться фантазированием, на тему "как бы было хорошо, если бы".

Мне хотелось бы видеть в вебе такое же разделение на "программу" и "документ", как в десктопах. Чтобы:

а) Программ относительно немного, по крайней мере, по сравнению с документами. На все страницы википедии будет полдюжины программ (там всё-таки есть разные страницы).

б) Документы не содержат исполняемый код. В данном случае, конечно, имеется в виду жабоскрипт. Сюда же, видимо, CSS.

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

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

А, да, прогноз: этого не будет.

15th January 2014

15:57: Мопед, в общем, не совсем мой...
...но нет ли желающих пописать на лучшем в мире объектно-ориентированном языке под названием Erlang? А то у нас в РекСофте стоит задача по-быстрому набрать ещё десяток человек на эрланг-проект (не передо мной стоит, слава монстру), а претенденты идут, мягко говоря, сТранНые.

Вилку зарплат не озвучу, ибо сам не знаю. Территориально - СПб, приблизительно равноудалённо от Площади Мужества, Пионерской, Чёрной Речки и, кажется, Удельной. В общем, добираться не очень. Но народ вменяемый. Erlang тоже.

7th January 2014

19:44: Булгаков — это голова
Дал объявление в spb_otdam_darom, предлагая свой старый, битый жизнью iPad. То, что началось в комментах и личных сообщениях, до боли напоминало классику:

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

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

iPad ушёл.

28th December 2013

23:29: По следам четвёртого раза
выкладываю видео и несколько фотографий.

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

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

Собственно, видео:

И немножко пикспама. Из начала номера:

Из середины:

Из конца:

Вместе с тренером:

И, до кучи: ещё один номер с бальными танцами (стандартом): http://www.youtube.com/watch?v=fiaYBk8QhyY

23rd December 2013

13:21: В четвёртый раз
потанцевали на отчётнике "Текилы". Опять в ДК Дзержинского.

Организовано всё было ГОРАЗДО лучше, чем в прошлый раз. Решили основную проблему - расписание; в этот раз его даже обогнали. Сделали, наконец-то, отдельные раздевалки для танцоров разного пола.

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

В общем, нам с нашим стандартом никто не мешал.

Собственно номер. Всю драматургию для него придумал я. Хореография - моя примерно на 75%. Ещё процентов двадцать придумала Оля, и пять - наш тренер, Лёша Задвигин. Налажать мы нигде особо не налажали, но мелкие помарки были - скажем, первый фолловэй в танго мы начали раньше времени. Я это вовремя заметил и попридержал движения, так что уже следующий такт пошёл в правильном ритме.

За основу номера я взял классическую латинскую тройку - самба (знакомство на карнавале), ча-ча-ча (продолжение знакомства в баре, где места поменьше) и румба (любовь). Сначала мне хотелось собственно это и станцевать, но меня хором убедили, что лучше танцевать стандарт. Я стал думать, как перенести это всё в стандарт, и в итоге пришёл к следующему: венский вальс (знакомство на балу; квикстеп тоже подошёл бы), танго (конфликт), и медленный вальс (любовь). Для конфликта нужен был повод, и я его нашёл: Оля нацепила на платье цветок, а я в конце венского вальса его сорвал и не стал отдавать. Как рифму к этому делу в конце номера я предложил ей целую розу (тут очень пригодилась "появляющаяся роза" из реквизита фокусников: её можно было сложить и спрятать в карман).

Фотографий пока нет, видео тоже. Обещают, что на этой неделе будут - я тогда сделаю новый пост.

13th December 2013

11:14: А мы монтажники-подводники
Решил перечитать повесть Джеффри Дженкинса "Берег скелетов". Когда-то давно читал её в подшивке какого-то журнала ("Вокруг света"? Не помню) и она мне очень нравилась. Это такой триллер про капитана рыболовного траулера.

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

И вот я думаю: ведь это ровно то, что нужно нам, программистам. Ну, правда, "свежий воздух" для нас - это "читабельность кода", а "скорость" нужна более асимптотическая, чем точная. Зато порядок, в котором они идут, тот, какой нужен.

Получается, что мы - своего рода подводники.


20th October 2013

20:00: Яблоки и математика
Обнаружил тут, что можно не только набирать тексты в LaTeX-е на iPad-е, но и там же их компилировать. Попробовал — оказалось чрезвычайно удобно. Добавил к этому ещё и внешнюю клавиатуру (Logitech UltraThin Keyboard Cover), превращающую iPad в миниатюрный ноутбук — вообще зашибись.

Сразу оговариваюсь: нет, нетбук не лучше. iOS и тачскрин уделывают нетбуки как нечего делать.

Приложений, умеющих компилировать LaTeX, оказалось аж два: Tex Writer и TexPad. Чем отличаются:

1) Оба изначально устанавливают только базовые пакеты, остальное надо докачивать отдельно; однако, Tex Writer это делает автоматически (в момент компиляции документа, эти пакеты использующего), а TexPad — по команде пользователя. В частности, поддержку русского в babel Tex Writer включил сам, когда понадобилось.

2) Tex Writer позволяет передать документ (как .tex, так и .pdf, и вообще любой) в другое приложение (хотя жест, с помощью которого это делается, не вполне очевиден). TexPad — вещь в себе, вытащить из него готовый PDF можно только через iTunes.

3) Разный подход к синхронизации с DropBox: Tex Writer просто синхронизирует все файлы, о которых знает (кроме texmf-local, хотя можно и его тоже синхронизировать), а TexPad требует отдельных указаний: это синхронизировать, это нет. Распечатать через AirPrint могут оба.

4) В Tex Writer используется дурацкая система перемещения курсора — вместо стандартной лупы там какая-то фигня со скачущим текстом. Привыкнуть можно, но смысл не ясен. В TexPad — всё стандартно.

4.1) Опять же, в Tex Writer перемещение курсора стрелками (физической клавиатуры) в сочетании с модификаторами либо не работает, либо работает неправильно. Скажем, Option-Up по идее должна перемещать на абзац выше, а на самом деле перескакивает в начало файла. Option-Down, аналогично, должна перемещать на абзац ниже, а на самом деле ТОЖЕ перескакивает в начало файла. В TexPad всё стандартно.

5) В Tex Writer показываются номера строк, в TexPad — нет. В обоих это не настраивается.

6) Оба умеют показывать логи. Tex Writer опознаёт в них номера строк и делает их гиперссылками. TexPad полностью заменяет лог на табличку со списком ошибок и предупреждений (которые, опять же, являются гиперссылками), и только по второму нажатию позволяет посмотреть полный лог.

7) Есть вещи, которые работают в TexPad и не работают в Tex Writer — вроде бы, beamer и tikz в их числе. Я сам пока не пробовал.

По поводу 4.1 я отправил багрепорт, автор Tex Writer-а обещал поправить. Кроме того, по его же словам в текущей версии кириллица не поддерживается; на самом деле поддерживается, если делать

Вариант с \usepackage{fontenc} не работает.

По пункту 4 я намекнул, что так делать не надо, но, похоже, автор упёрся.

Сам пока, вероятно, останусь на Tex Writer-е, пока не столкнусь с ограничениями.

Update: TikZ в Tex Writer работает (по крайней мере, простые примеры).

Update 2: То же относится к Beamer-у.

27th August 2013

14:39: Вспоминая классику
Вот допустим, случилась война (не дай бог, конечно) между РФ и кем-то ещё. Ну, скажем, Португалией. До ядерного оружия не дошло, потому как у Португалии его нет, а РФ опасается, что обидится остальная Европа, когда на неё отнесёт радиоактивное облако, и вместо одного противника получится десяток.

И вот РФ, среди прочего, строит фальшивый аэродром из фанеры, чтобы, значить, португальские бомбардировщики отвлечь от настоящих военных объектов. И посреди строительства над этим аэродромом появляется португальский самолёт и сбрасывает фанерную бомбу.

Как вы думаете, сколько ещё будет продолжаться строительство аэродрома?

22nd August 2013

15:50: Переполнение стека
Я редко читаю ЖЖ.

То есть, да, я часто ОТВЕЧАЮ в ЖЖ. Но я редко открываю сайт livejournal.com, чтобы что-то прочесть. Как правило, посты валятся ко мне в виде RSS, кэшируются, после чего я могу читать их в метро, где нет связи, или перед началом тренировки, когда связь есть, но очень плохая. А вот за настольным компьютером я читаю ЖЖ редко. Это неудобно. Всё, что есть на настольном компе — это браузер.

Так вот. Есть какие-нибудь инструменты, облегчающие работу со stackoverflow? Точнее: облегчающие поиск вопросов, на которые можешь ответить, и, соответственно, написание ответов? Необязательно мобильные, можно и десктопные — но хоть чуточку более заточенные под SO, чем браузер?

15th August 2013

15:12: Прокниги
1. Майкл Дибдин, "Последний рассказ о Шерлоке Холмсе". Кто-нибудь, объясните мне, на черта я это прочитал? Глупо, плоско, затянуто. Жалко времени.

2. "Пасть льва и пельмени" этого, ну, сами знаете. Сдаюсь. Не могу прорваться через эту тягомотину. Я могу некоторое время жевать картон, но всему же есть предел. Да, кстати, сериал я тоже не смог посмотреть — но там всё портила, в основном, мерзкая рожа Шона Бина. По крайней мере, я не столько его смотрел, чтобы понять, картон это или не картон.

3. Мариам Петросян, "Дом, в котором..."

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

Стоял тот дом — всем жителям знакомый,
Его ещё Наполеон застал.
Но вот его назначили для слома,
Жильцы давно уехали из дома,
Но дом пока стоял.

В доме.

В этом Доме жильцы есть. Их много, и они остаются там практически до самого конца Дома, а некоторые — и после. И всё-таки это почти тот же дом — в нём тоже, порой, происходит такое, что иной дворник бросит лопату и поспешит на выход.

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

От страха дети больше не трясутся,
Нет дома что два века простоял,
И скоро здесь по плану реконструкций
Ввысь этажей десятки вознесутся —
Бетон, стекло, металл.


13th August 2013

16:17: Ленивость в окамле
utop[0]> open Core.Std;;
utop[1]> let a = lazy (printf "A\n"; 0);;
val a : int lazy_t = <lazy>
utop[2]> let b (a : int) = lazy (printf "B\n"; 0);;
val b : int -> int lazy_t = <fun>
utop[3]> Lazy.force Lazy.(a >>= b);;
- : int = 0

Ну ё-моё...

1st August 2013

00:41: Пиратское
Где-то мне попалось очень хорошее сравнение. Именно, пиратское скачивание кина и проч. больше похоже не на воровство, а на нарушение границ частных владений (то, что супостаты называют ёмким словом trespassing). То есть, если посторонний человек ходит по вашему участку, ничего не портит, не ломает (даже забор — потому как вошёл через здоровенную дыру, которую у вас уже год руки не доходят заделать), вам дорогу не загораживает — вы всё равно постараетесь вытолкать его в шею, и будете при этом правы.

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

а) Другого способа попасть куда вам нужно просто нет. Например, частные владения расположились плотным кольцом вокруг озера, которое никакому частному лицу не принадлежит, и вы хотите в нём искупаться.

б) Участок уже лет дцать как заброшен. Хозяин не появляется, стоявший там домик рассыпался на брёвна-кирпичи, вся территория заросла крапивой, забор сгнил до полного отсутствия, и других признаков частного владения, кроме записи где-то там в реестре, не осталось.


Это я, естественно, к ситуации со старыми фильмами — которые, зачастую, кроме как спиратив, добыть нельзя вообще.

22nd July 2013

23:29: О!
Господа, я считаю, что это шикарно:

28th May 2013

23:01: Один раз — случайность, два — совпадение, три — правило.
Вчера был третий отчётник "Текилы", в котором мы принимали участие. На сей раз — в Доме Офицеров.

Место было, надо сказать, похуже, чем ДК Дзержинского, где мы были в прошлый раз. Сцена — примерно такая же, с тем же прорезиненным полом. А вот гримёрки — в каких-то катакомбах, душные до ужаса.

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

Зато перед началом концерта нам дали прогнать номер на сцене. При этом мы поругались со звукооператором — мы ему говорим, под каким номером мы записаны в программе, а у него список немного отличается, и под этим номером там какая-то муть.

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

Лёша Задвигин, наш тренер, на этот раз нарушил традицию и таки приехал нас поддержать. Нам было очень приятно.

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

Как обычно — видео:

Ещё одно видео, покрупнее, но, соответственно, когда пары расходятся в разные стороны, на это видео подчас не попадает ни одна:

30th April 2013

15:01: Роутинг
Что у нас есть для роутинга в WAI:

Пакет wai-router требует wai < 1.3. Современный wai - 1.4.0.

Пакет web-routes-wai требует wai < 1.4. Чуть-чуть не достаёт.

Пакет wai-middleware-route требует http-types 0.7.*. Современный http-types - 0.8.0.

Пакет wai-lite помечен с опечаткой как DEPCRECATED, рекомендует использовать simple.

Пакет simple требует установленно postgresql. Никакого флага, чтобы это отключить, нет.

Пакет wai-dispatch писал кто-то альтернативно одарённый, решивший, что к пути запроса вполне логично будет добавить метод, т.е. запрос к "http://server/a/b/c" роутится на ["GET", "a", "b", "c"]. Отразить это в документации этот кто-то не позаботился.

Пакет wai-routes работает через Template Haskell.

Что у нас есть для роутинга в Happstack:

Базовый пакет happstack-server содержит всё необходимое.

Что я упустил?

20th April 2013

19:28: Покатушечное
Вообще-то, всё закончилось уже несколько часов как, но я только сейчас сподобился об этом написать.

Итак, сегодня было торжественное открытие летнего велосипедного сезона в клубе "Велопитер". Отмечали это заездом на 60км (это они так говорят — по ощущениям, там было где-то 45, ну, максимум, 50). Я в клубе не состою, но скатался тоже.

Почти всю дорогу моросил дождь, распогодилось только к концу. Некоторые ехали в плащах-дождевиках. Я ехал так, и, в общем, промок не сильно. Отдельные у-о ехали на велосипедах без крыльев — за одним таким я некоторое время следовал; представьте — от колеса летит фонтан жидкой грязи, причём (так как крыла нет) летит не назад, а почти вертикально вверх и даже чуть-чуть вперёд, и упирается непосредственно в свисающую с седла задницу, точно посередине.

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

Ехал я ближе к хвосту колонны — я не слишком высоко оцениваю свои способности как велосипедиста. Обошлось без происшествий, если не считать того, что у меня посреди дороги разболталось зеркало, и я остановился его подтянуть. Очень порадовался при этом, что перед выходом сунул в рюкзак разводной ключ — он у меня хороший, 12-дюймовый, затягивает гайку любого размера, откручивает даже то, что приварено, и если нападут разбойники — им очень сподручно отмахиваться.

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

В целом, покатались вполне приятно. У меня был с собой айфон, но фотографировал я мало, не до того было. Одну фотографию, всё-таки, выкладываю — я её подрезал слегка, чтобы понятнее было.
Read more...Collapse )

11th April 2013

18:55: Путезависимое
Что-то работается сегодня не очень. Напишу, пожалуй, что-нибудь сине-зелёное.
> {-# LANGUAGE Rank2Types #-}
> module PathDependent where

Вот, есть такой классический тип Set. Множество, стало быть. Как известно, оно требует, чтобы элементы, лежащие в нём, принадлежали классу Ord. Ну, внутри у него сбалансированное дерево, которое без упорядоченности не может.

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

То есть, фактически, интерфейс, предоставляемый типом Set примерно такой (я привожу интерфейс не полностью, а на "реализацию" рекомендую не смотреть вообще, она здесь только для примера):
> data Set a = Set
> empty :: Set a
> empty = Set
> insert :: (a -> a -> Ordering) -> a -> Set a -> Set a
> insert _ _ ~Set = Set
> check :: (a -> a -> Ordering) -> a -> Set a -> Bool
> check _ _ ~Set = False

Ну и, естественно, здесь мы уже вообще не контролируем, что первый аргумент (типа (a -> a -> Ordering)) будет одним и тем же. А если он будет меняться — наше множество непременно поплывёт. Может, например, оказаться, что один и тот же элемент окажется в нём несколько раз. Или, что ещё хуже, что функция check не найдёт в множестве элемент, который там точно есть. И так далее.

Соответственно, нам нужно не передавать каждый раз функцию сравнения в аргументе, а хранить её где-то ещё. И первое, что приходит в голову - хранить её в самом множестве. Вот так, например:
> data GSet a = GSet (a -> a -> Ordering) (Set a)

Так, действительно, можно обезопасить указанный интерфейс. Функцию сравнения придётся перенести в другое место, но это не страшно:
> emptyG :: (a -> a -> Ordering) -> GSet a
> emptyG comparator = GSet comparator empty
> insertG :: a -> GSet a -> GSet a
> insertG a (GSet comparator s) = GSet comparator (insert comparator a s)
> checkG :: a -> GSet a -> Bool
> checkG a (GSet comparator s) = check comparator a s

Всё, казалось бы, хорошо. Проблемы начинаются, когда множеств-аргументов оказывается больше одного. Например, операция объединения рушит всю схему:
> union :: (a -> a -> Ordering) -> Set a -> Set a -> Set a
> union _ ~Set ~Set = Set

unionG :: GSet a -> GSet a -> GSet a
unionG (GSet comparator1 s1) (GSet comparator2 s2) = GSet ??? (union ??? s1 s2)

И что ставить вместо ???? Один из компараторов? Который? А второй что — потерять? А то, что операция получится некоммутативной — ничего? Или поставить один в одном месте, другой — в другом?

Единственный разумный выход — это преобразовать одно из множеств в список и добавить его элементы во второе по одному. Но это — медленная операция. По крайней мере, медленная в сравнении с объединением упорядоченных деревьев.

На этом месте продвинутые читатели подумали "Ха! Зависимые типы!" И да, если бы в Хаскеле были зависимые типы, то мы написали бы что-то в таком духе:
newtype SetDT a (comparator :: a -> a -> Ordering) = SetDT (Set a)

Теперь компаратор хранится не в самом множестве, а в его типе. Поэтому за совпадением этих компараторов может проследить автоматика, то есть, система типов. Интерфейс получается примерно таким:
emptyDT :: (comparator :: a -> a -> Ordering) -> SetDT a comparator
emptyDT _ = SetDT empty

insertDT :: a -> SetDT a comparator -> SetDT a comparator
insertDT a ~(SetDT s) = SetDT (insert comparator a s)

checkDT :: a -> SetDT a comparator -> Bool
checkDT a ~(SetDT s) = check comparator a s

unionDT :: SetDT a comparator -> SetDT a comparator -> SetDT a comparator
unionDT (SetDT s1) (SetDT s2) = SetDT (union comparator s1 s2)

Собственно говоря, полноценные зависимые типы не обязательны, достаточно того, что в Scala называется path-dependent types. Это более слабая, но и более простая фишка. Суть в том, что тип зависит не от значения, а от указателя на значение. В результате требуемые зависимыми типами доказательства исчезают — зачем доказывать, что два значения совпадают, когда они хранятся в одной переменной.

Так что, Scala может сделать безопасный интерфейс, а мы не можем? Не бывать такому!

Добавим новый тип, который будет своего рода "флагом" для нашего значения:
> newtype Comparator r a = Comparator (a -> a -> Ordering)
> newtype SetPD r a = SetPD (Set a)

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

Интерфейс получается практически идентичный тому, который был приведён в начале поста:
> emptyPD :: SetPD r a
> emptyPD = SetPD empty

> insertPD :: Comparator r a -> a -> SetPD r a -> SetPD r a
> insertPD (Comparator cmp) a (SetPD s) = SetPD (insert cmp a s)

> checkPD :: Comparator r a -> a -> SetPD r a -> Bool
> checkPD (Comparator cmp) a (SetPD s) = check cmp a s

> unionPD :: Comparator r a -> SetPD r a -> SetPD r a -> SetPD r a
> unionPD (Comparator cmp) (SetPD s1) (SetPD s2) = SetPD (union cmp s1 s2)

Ну что ж, это всё хорошо, но мы не решили проблему, а сдвинули её. Теперь нам нужно как-то гарантировать, что все используемые нами значения типа Comparator r a совпадают. Точнее даже, что мы используем только одно значение этого типа. И в этом нам поможет полиморфизм, вместе с такой функцией:
> withComparator :: (a -> a -> Ordering) -> (forall r. Comparator r a -> b) -> b
> withComparator cmp h = h $ Comparator cmp

Фокус в том, что мы не будем экспортировать конструкторы для типов Comparator и SetPD. Мы экспортируем только интерфейс SetPD и функцию withComparator. А значит, эта функция окажется единственным способом создать компаратор. При этом она не даст нам создать компараторы одного типа — точнее, полиморфизм не позволит нам утверждать, что компараторы относятся к одному типу, а это ничем не хуже. Ну, разумеется, если кто-то решит поработать функцией unsafeCoerce, то он сам себе злобный буратино.

Проверяем, как оно работает. Первый тест:
> test1 =
>     withComparator compare $ \c ->
>     checkPD c 1 $ insertPD c 2 $ insertPD c 1 $ emptyPD

Этот тест проходит совершенно нормально, он вполне законный. Попробуем использовать два разных компаратора:
> test2 =
>     withComparator compare $ \c1 ->
>     withComparator (flip compare) $ \c2 ->
>     checkPD c1 1 $ insertPD c2 2 $ emptyPD

Получим ошибку компиляции:
    Couldn't match type `r1' with `r'
      `r1' is a rigid type variable bound by
           a type expected by the context: Comparator r1 Integer -> Bool
           at PathDependent.lhs:57:7
      `r' is a rigid type variable bound by
          a type expected by the context: Comparator r Integer -> Bool
          at PathDependent.lhs:56:7
    Expected type: SetPD r Integer
      Actual type: SetPD r1 Integer
    In the second argument of `($)', namely `insertPD c2 2 $ emptyPD'
    In the expression: checkPD c1 1 $ insertPD c2 2 $ emptyPD
    In the second argument of `($)', namely
      `\ c2 -> checkPD c1 1 $ insertPD c2 2 $ emptyPD'
Failed, modules loaded: none.

Полиморфизм вообще не позволит нам вытащить ни множества, ни сам компаратор, из аргумента функции withComparator:
> test3 =
>     withComparator compare $ \c ->
>     insertPD c 2 $ insertPD c 1 $ emptyPD

Получаем, опять-таки, ошибку:
    Couldn't match expected type `b' with actual type `SetPD r Integer'
      `b' is a rigid type variable bound by
          the inferred type of test3 :: b
          at PathDependent.lhs:50:3
    In the expression: insertPD c 2 $ insertPD c 1 $ emptyPD
    In the second argument of `($)', namely
      `\ c -> insertPD c 2 $ insertPD c 1 $ emptyPD'
    In the expression:
      withComparator compare
      $ \ c -> insertPD c 2 $ insertPD c 1 $ emptyPD
Failed, modules loaded: none.

Интерфейс полностью безопасен. При этом нам никто не мешает аргумент функции withComparator разбивать на подфункции, которые знать не знают ничего ни про какие {-# LANGUAGE Rank2Types #-}. Главное, чтобы они сохраняли полиморфность по r.


23rd March 2013

03:23: То, что надо
Кинули тут в твиттере линк: http://hackage.haskell.org/trac/ghc/ticket/7642

Вкратце: тайпклассы БЕЗ параметров. У такого тайпкласса, естественно, может быть только один инстанс, так что кажется, что это то же самое, что и просто значение. Но один юзкейс я вижу. Это форвард-декларации. То есть "я предоставлю это значение, но не здесь, а в другом модуле, который сюда импортировать не хочу или не могу". То, что в каких-нибудь плюсах есть просто с рождения.

Для типов, кстати, форвард-декларации есть, это семейства типов без параметров. Они работают прекрасно.

Пейтон-Джонса, в итоге, убедили, что реализовать это надо.

14th March 2013

11:33: Тонущий пост
Ну, главную новость дня все слышали, да? Нет, я не про папу римского. Кому на фиг нужен этот папа римский? Если его кому-то не хватает, пусть кликнет по десктопу правой кнопкой мыши и выберет пункт "создать папку".

Я про гугль-ридер. Чем, собственно, он был (и пока остаётся) так хорош для меня?

1) Облачный сервис. Да, я часто пользуюсь ридером с разных компов. С десктопных (коих тоже не один) я, как правило, только добавляю RSS. С мобильных (и их не один) - читаю. И хочу видеть только то, что ещё не прочитал, ни с этого устройства, ни с другого.

2) iOS-приложение для доступа к нему. Более того: не одно приложение. Дофигищи приложений, если уж на то пошло. Я пользовался NewsRack. Нет, я не помню, почему я не стал пользоваться <вставьте своё любимое приложение>. Это было давно. Всё, что мне нужно - это читать, и добавлять в Instapaper.

Собственно, всё. Мне глубоко по барабану sharing. Читать чужой пост только потому, что его читает твой "френд" - это полный идиотизм. Особенно если этот френд не удосужился черкануть пару строчек о том, чем этот пост так уж интересен.

Мне глубоко плевать на веб-интерфейс ридера. Не буду врать, я им пользовался, но раза три в год. Я не пострадал бы, если бы его не было.

Мне глубоко пофиг "звёзды" - если мне понравится чей-то пост, я его букмаркну.

Но пункты 1 и 2 были killer features. Я не знаю, как быть без них.

23rd February 2013

13:57: Сообщения об ошибках
Среди компьютерно грамотного населения ходит в разных вариантах байка о тупом юзере, который увидел на экране сообщение об ошибке, не прочитал его, нажал "OK", а потом побежал спрашивать "А что это было?"

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

Чаще всего это юридические тексты. Что очень печально, так как такой текст может сильно ушибить. Но бывают и другие, вот, у avva приводится цитата из Розенталя, например. Я скопипащу её сюда:
При выборе варианта в парах внутри них – внутри их (с н перед местоимением 3-го лица или без н) следует исходить из того, что в современном языке указанный звук добавляется, если местоимение стоит после любого из простых, или первообразных, предлогов (без, в, для, до, за, из, к, на, над, о, от, по, под, перед, при, про, с, у, через), а также после многих наречных предлогов (возле, вокруг, впереди, мимо, напротив, около, после, посреди, сзади и некоторых других, употребляющихся с родительным падежом). Однако такие предлоги, как внутри, вне, употребляются в основном без начального н.
Не добавляется н к местоимению также после предлогов наречного происхождения, управляющих дательным падежом, ср.: вопреки ему, наперекор ей, согласно им, вслед ему, навстречу ей, подобно им, соответственно им; также: благодаря ему.
Не требуют после себя вставки н также сложные предлоги в сочетании с местоимением, например: в отношении его, при помощи ее, не в пример им, в противовес ему, по поводу ее, за исключением их, со стороны его, по причине ее; также: наподобие его, насчет их.
Не добавляется начальное н в тех случаях, когда местоимение стоит после сравнительной степени прилагательного или наречия, например: старше его, выше ее, лучше их.
Если личному местоимению предшествует определительное местоимение весь то допустимы обе формы (со встречным н и без него,), например: у всех их – у всех них, для всех их – для всех них, за всеми ими – за всеми ними, над всеми ими – над всеми ними.
Вариантные формы встречаются и в других случаях отрыва местоимения 3-го лица от предлога в результате вставки между ними какого-либо другого слова, например: между вами и ими – между вами и ними, между мной и им – между мной и ним. Ср.: Видишь разницу между нами и ими... (Горький). – ...Нет между нами и ними никакой средней линии (Гайдар).
Ну невозможно же!

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

8th February 2013

16:33: Instapaper

Сайт http://www.instapaper.com предназначен для того, чтобы закинуть туда ссылку, а потом, возможно, за другим компьютером, по этой ссылке пройти и прочитать. Почему сразу не прочитать? Времени нет, канал паршивый, просто в лом... масса причин.

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

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

Так вот (добрались до сути). Нет ли аналогичного сервиса - но для картинок?

Что нужно:

1) Хранение ссылок на картинки. (ваш к.о.)

2) Предпросмотр картинок - может быть, с масштабированием, или ещё как-то. Необязательно, чтобы эти превьюшки хранились именно на этом сервисе, можно тягать их с исходных адресов и масштабировать css-ом. В сущности, даже желательно, чтобы так происходило - а то возможно, что картинка исчезнет, а превьюшка останется.

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

4) Букмарклет - чтобы делать то же самое из любого браузера.

5) Хорошо бы: какой-то способ разграничить показываемые картинки. Чтобы, например, открыв на работе свой список сохранённого добра ты не выставлял на всеобщее обозрение картинки с любимых порносайтов.

Кто-нибудь что-нибудь подобное знает?

3rd February 2013

22:33: Интересно, типа.
Вот есть, типа, такая типа штука, называется типа "зависимые типы". Когда сам тип содержит в себе значение. И два таких типа будут (типа) совместимы, если эти значения равны. А поскольку значения будут известны только в рантайме, приходится давать доказательство того, что значения таки равны.

А вот во всяких джавах с сиплюсплюсами равенств как минимум два. Не помню точно, как они называются, но, в общем, равенство по ссылке и по значению. Первое сильнее второго. То есть, если какие-то штуки лежат в одном и том же месте, то это одна и та же штука, и, значит, они одинаковые. Но если они одинаковые — это ещё не значит, что они лежат в одном и том же месте.

В агде, если мой эклер меня не обманывает, требуется равенство по значению. А есть ли зависимые типы с равенством по ссылке? То есть, для того, чтобы Vector n Int был тем же типом, что и Vector m Int нужно не только n=m, нужно, чтобы n и m были одной и той же переменной.

Такое где-нибудь есть?

Update: подсказали, что это, вроде, называется "path dependent types".

1st February 2013

11:41: Команда ублюдков
решила, что они лучше всех знают, какой интернет народу нужен. Пока, как я понимаю, в Костромской области.

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

Список уродов из попечительского совета этой "лиги":

  • Чиновная сволочь:

    Щеголев Игорь Олегович
    Помощник Президента Российской Федерации

    Мизулина Елена Борисовна
    Государственная дума РФ (ну, какое ж дрянное дело без неё обойдётся)

    Ситников Сергей Константинович
    Губернатор Костромской области

    Толстой Пётр Олегович
    Общественная палата РФ

    Торшин Александр Порфирьевич
    Совет Федерации РФ

  • Сволочь в погонах:

    Герасимов Андрей Васильевич
    ФСБ России

    Мошков Алексей Николаевич
    МВД России

    Подноскова Анастасия Анатольевна
    Следственный комитет

    Чибрин Валерий Петрович
    ФСКН России

    Шамшина Ольга Геннадьевна
    Генеральная прокуратура РФ

  • Прочая сволота:

    Касперский Евгений Валентинович
    Генеральный директор ЗАО "Лаборатория Касперского" (этого давно пора давить)

    Легойда Владимир Романович
    Московский Патриархат (ну, тут сволочизм профессиональный)

    Гришин Дмитрий Сергеевич
    Mail.Ru Group (не лучший способ отмыться от последнего скандала)

    Малофеев Константин Валерьевич
    Лига безопасного интернета (рекурсия — такая рекурсия)

    Кудряшов Антон Владимирович
    ОАО «ВымпелКом»

    Провоторов Александр Юрьевич
    ОАО "Ростелеком"

    Солдатенков Сергей Владимирович
    ОАО «Мегафон»

    Шамолин Михаил Валерьевич
    АФК «Система»

    Юрьев Евгений Леонидович
    Деловая Россия

    Борода Александр Моисеевич
    Федерация еврейских общин России (а этих как сюда занесло???)

Пока они милостиво дают право отказаться от этого. Пока.
Update: администрация Костромской области пошла на попятный:

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

Маразм остаётся маразмом, но, кажется, не столь фатальным.

11th January 2013

18:21: ВЛИУСЕРное, для lionet
Контекст: интервью Рукшина.

Ещё немного контекста, если кто не знает. С.Е. Рукшин - человек, лично ответственный за разрушение образования в 239-й школе. Оседлав волну превращения хобби для яйцеголовых "математические олимпиады" в большой спорт, он создал структуру кружков, которая погребла под собой всё остальное. Настолько, что человек, добившийся успехов в олимпиадном спорте, может не беспокоиться вообще ни о чём. Говорю по собственному опыту - я лично объехал выпускные экзамены именно с помощью олимпиад. Правда, кружковщины я в своё время избежал, и до сих пор этому радуюсь.

Поэтому заявления типа "он умудрился взрастить двух филдсовских лауреатов" иначе как БСК ("бред сивой кобылы", а не цвета российского флага) я назвать не могу. В конце концов, некоторое время Рукшин рассказывал в школе, что я, якобы, его ученик.

Для буквоедов: да, когда перед Рукшиным замаячила морковка звания "Соросовский учитель", он полгода вёл у нас какой-то бред (потому что "Соросовского учителя" давали только тем, кто реально преподаёт в школе, а не только кружки ведёт).

Далее, собственно по "интервью". Интервью строится по простенькой демагогической схеме: "они со мной не согласны, значит, они козлы и уроды ваще". Аргументация, естественно, на нуле. Например: "Более 60% населения не одобряют ЕГЭ, но он входит в закон". Это - единственный аргумент против ЕГЭ, который приводит Рукшин. Думаю, фразу "миллионы мух не могут ошибаться" он знает, но ему плевать.

Справка: я сам в своё время был горячим противником ЕГЭ. Первые экзамены, особенно по математике, были просто ужасны. Прошло немного времени. Я видел ЕГЭ, который сдавал в прошлом году мой брат. То, что было "ужас-ужас-ужас", стало более чем достойным экзаменом. И теперь я лично считаю, что ЕГЭ - лучшее, что было за последние лет двадцать сделано в образовании. Кстати, мне интересно, почему Рукшин выступает против системы, исключающей взятки?

Бред по поводу "Гражданами России нас делает блаблабла" я даже комментировать не хочу. С таким подходом надо возрождать пионерлагеря и игру "Зарница".

Встречаются в интервью удивительные вещи. Например: "в списки победителей финалов всероссийских олимпиад много лет вносились фамилии детей, которые в них вообще не участвовали. Соответственно, они получили денежные премии и льготы при поступлении в вуз" - извините, но я НИКОГДА не поверю, что Рукшин этих списков не видел.

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

25th December 2012

22:05: Юрьев день
Наткнулся на язык Rust. Позиционирует себя как "C, сделанный человеком, знающим Haskell". Читаю официальный туториал — и понимаю: да, так и есть. Алгебраические типы. Замыкания. Классы типов (называемые трейтами, но всем ведь всё понятно). И одновременно — язык достаточно близок к машине: не чисто функциональный, с указателями (причём, безопасными) — ну супер.

А потом натыкаюсь на такой пассаж:
The Rust compiler compiles generic functions very efficiently by monomorphizing them. Monomorphization is a fancy name for a simple idea: generate a separate copy of each generic function at each call site, a copy that is specialized to the argument types and can thus be optimized specifically for them. In this respect, Rust's generics have similar performance characteristics to C++ templates.
Ып. Вот тебе, бабушка, и сабж. Никакие это не дженерики, а обычные темплейты, только обрезанные. Попробовал на всякий случай свой тест — и, ЧСХ, Rust его зафейлил с совершенно невнятным сообщением об ошибке.

И сразу у меня впечатление, что делал этот язык не "человек, знающий Haskell", а "человек, прочитавший пару страничек из Душкина".

18th December 2012

11:35: Для памяти
К настоящему моменту почти пятьдесят тысяч детей из России нашли приёмных родителей в США.

Шестнадцать из них были убиты приёмными родителями.

Дэвид Полрейс, убит матерью Рене. 18 лет тюрьмы (выпущена досрочно через 10 лет за хорошее поведение).

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

Виктор Маттей, убит родителями. Оба получили 10 лет.

Люк Эванс, убит матерью. Мать оправдана.

Джейкоб Линдорф, убит матерью. Шесть лет.

Захария Хигир, убит матерью (признала свою вину). Четыре года.

Мария Беннет, убита матерью Сьюзен (признала свою вину). Три года.

Джессика Хэгман, убита матерью Патрицией (признала свою вину). Десять лет условно.

Лиам Томпсон, убит обоими родителями (отец обварил его кипятком, мать очень долго не обращалась к врачу). Оба родителя получили по 15 лет.

Алекс Павлис, убит матерью Ирмой. Мать получила 12 лет.

Денис Мерримэн, заморен родителями до смерти. Родители сели на 19 лет.

Нина Хилт, убита матерью Пегги. 25 лет.

Исаак Дистра, убит отцом Брайаном. Отец оправдан.

Николай Емельянцев (фамилия — по приёмному отцу, гражданину России), убит матерью Кимберли. 15 лет.

Чейз Харрисон, забыт отцом Майлзом в машине, где умер от перегрева. Отец оправдан.

Натаниэль Кравер, убит обоими родителями. Родители отбыли только досрочное (полтора года), кроме того, лишились дочери Элизабет, также приёмной.

Итого, из 16 случаев только три оправдания, плюс одно условное, плюс ещё один случай, когда суд ограничился досрочным.

Мне интересно, сможет ли кто-нибудь перечислить поимённо детей, убитых русскими приёмными родителями. И сроки.

3rd December 2012

10:59: Аччёт.
Коротко: фух.


Позавчера, в субботу, снова был отчётник Tequila Dance. На этот раз не под открытым небом, а в ДК Дзержинского (который уже давно не Дзержинского, но всё равно так называется). Мы танцевали дважды, медленный вальс в первом отделении (концерта, а не того, что вы подумали), и фигурный вальс (на основе венского) во втором.

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

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

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

Я первый раз в жизни танцевал во фраке. Честно говоря, разницы особой не почувствовал, разве что воротничок упирался в подбородок; но это не мешало.

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

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


8th November 2012

22:37: Просветительский пост по заказу nponeccop
Утверждение, что на понимание чего угодно требуется 10 лет, не имеет ничего общего с действительностью.

31st October 2012

10:50: Доделал библиотеку
Лежит на Hackage. Называется по-простому - plat. Это, собственно, те темплейты, которые мне были нужны. Собственно, выложил я это дело ещё вчера, но собралось оно на сервере Hackage только сегодня.

Библиотека маленькая, поэтому экспортирует ровно один модуль, хотя исходников заметно больше. В самих исходниках чистый Haskell98, вполне себе Safe, но при этом активно используется mtl (которая не Haskell98). Причём это не было самоцелью - я был вполне готов использовать расширения, если понадобится. Не понадобилось. Даже один инстанс, который, как я думал, будет лучше написать через GeneralizedNewtypeDeriving, на поверку оказался немного не таким.

Из возможностей - вставка строк (естественно), итерация, ветвление, проверка булевских условий. Немного, но то, что нужно.

18th October 2012

23:54: Хотел написать программный пост про то, как я не люблю генераторы кода. Причём любые. Сюда попадают макросы: CPP, Лисп (считай, целиком), Template Haskell, да всё подряд. И внешние препроцессоры — например, тот же CPP, когда он используется отдельно от C. Отдельной строкой сюда идут шаблонизаторы, генерирующие программный код — как в HSP, скажем. И всякие безумные тулзы, генерирующие "заготовки" сайтов, как это делает, например, Snap (и я уж молчу про разные джанги).

Не получилось. Потому что есть один язык генерации кода, который я могу терпеть. Он абсолютно ублюдочен. По сравнению с ним, синтаксис того же Template Haskell — это произведение искусства. Он завязан на единственный язык, и оторвать его невозможно. Его не получится использовать без интенсивной гуглёжки. И всё же я могу терпеть его наличие в коде и даже писать на нём сам.

Называется — шаблоны C++.

14th October 2012

03:56: Библиотеки
Слушайте, это я плохо ищу, или никто так и не сподобился написать нормальную библиотеку темплейтов для хаскеля?

Что пробовал:
HStringTemplate не ставится (ему нужно syb-with-class — только не спрашивайте, зачем — а оно не компилируется).
Heist требует вывернуться ужом, чтобы сделать простейший цикл.
Twine не даёт использовать в шаблоне собственный тип данных без UndecidableInstances (НАФИГА???)
Hastache каждый раз заново переинтерпретирует шаблон.

Куча библиотек, требующих использовать template haskell.

Ещё несколько библиотек, обрабатывающих шаблоны внешней утилитой (то есть, тот же template haskell, только ещё хуже).

У меня страшное подозрение, что библиотеки темплейтов пишут исключительно идиоты. В итоге я использую банальный Text.Html и чувствую себя полным бараном.

5th October 2012

15:42: GeneralizedNewtypeDeriving
Дважды мудак обратил моё внимание на пример того, как расширения
> {-# LANGUAGE GADTs #-}

> {-# LANGUAGE GeneralizedNewtypeDeriving #-}

дают возможность сделать unsafeCoerce. Продублирую здесь, так как информация важная; оба расширения я использую достаточно часто, и мне не хотелось бы получить ошибку в рантайме.
> module UnsafeCoerce where

Итак, сооружаем тип, который засвидетельствует для нас, что два типа равны:
> data Same a b where Same :: Same a a

Ну, коль скоро они равны, один из них можно безопасно преобразовать в другой:
> coerce :: Same a b -> a -> b
> coerce Same a = a

Нам понадобится простейшее утверждение, что если один тип равен двум другим, то они равны между собой. Мне это несколько напомнило аксиому о параллельных, отсюда название функции:
> euclid :: Same a b -> Same a c -> Same b c
> euclid Same Same = Same

Пока всё хорошо.

Теперь заведём класс, принадлежность типа к которому означает, что этот тип — не что иное как ():
> class Unit a where unit :: Same () a

Ну и очевидный инстанс:
> instance Unit () where unit = Same

А вот теперь мы заведём новый тип, который будет притворяться ():
> newtype Tag a = Tag () deriving Unit

Фокус в том, что deriving Unit заставляет класс Unit солгать, что тип, дескать, и есть такой.

Ну, казалось бы, что в этом такого? Типы разные, но изоморфные, так что эта ложь кажется не такой уж ужасной. Однако, её можно развить:
> same :: Same (Tag a) (Tag b) -> Same a b
> same Same = Same

То есть, из того, что два (разных) типа равны, можно сделать вывод, что любые два типа равны.

Осталось только собрать всё это воедино:
> unsafeCoerce :: a -> a'
> unsafeCoerce = coerce $ same $ euclid unit unit

Вот. Всё это очень плохо. Получается, что мы мешаем две вещи: изоморфизм типов и их синтаксическое равенство. deriving Unit основывается на изоморфизме, а same Same = Same — на равенстве.

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

Update: в комментах помогли сформулировать, чем мне не нравится same Same = Same: даже если под табличками "яблоки" и "бананы" стоит одно и то же ведро говна, это не значит, что яблоки ничем не отличаются от бананов.

27th September 2012

21:34: Нашёл в ЖЖ, понравилось чрезвычайно
Это скорее бзик верующих, считать всё вокруг верой, вне зависимости от того, является ли оно ей. Придумают себе чудо-ёлку и водят вокруг неё хоровод, будучи при этом уверенными, что и все остальные люди точно также водят хоровод вокруг ёлки, сосны, кактуса или хотя бы саксаула. Картина мира, при которой вся эта религиозная ботаника стоит в одном тёмном и пыльном углу под табличкой «Психотехники порабощения в обычаях народов мира» для понимания верующих недоступна (иначе бы они не были верующими).
Powered by LiveJournal.com