to post messages and comments.

Посоветуйте, кто пользовался, хороший LRU для хаскеля (или как искать). При том, что скорее всего придётся немного допилить его API под конкретную нужду (а может взять и свой небольшой написать?).

Паттерн использования такой: идёт поток ивентов, среди них нужно учитывать только последний по какому-то id-полю. То есть пока я думал сделать LRU-кеш, переписывая по этому самому id-полю значения, при удалении из LRU считать объект "конечным", также при окончании ивентов всё, что внутри LRU считать конечным.

Палю метод улучшения вашего грепа для поиска по текстовым исходникам (кроме различных масок файлов и директорий):

M-x customize-group
grep

В поле `grep-find-command` вместо

'("find . -type f -exec grep -nH -e {} +" . 34)

Ставьте:

'("find . -type f -exec cut -c1-2000 | grep -nH -e {} +" . 34)

Таким образом каждая линия будет обрезаться до первых 2000 символов при поиске. Мне лично это как раз то, что нужно.

Вопрос к читавшим Functional Data Structures Окасаки. Вы читали вникая в доказательства или нет? То есть, я сейчас прочитал до места, где сложность очередей доказали через Banker's и Physicist Method'ы, и осознал, что либо мне нужно перечитывать всё с самого начала (а перед этим желательно почитать много разных примеров попроще по доказательству при помощи амортизации), либо забить и читать доказательства поверхностно, а внимательно читать только код.

Вот, думаю начать младшего брата постепенно учить программированию. Решил начать со схемы (заодно и сам поучу), поставил Racket. Изначально думал взять SICP (который я уже прочёл и знаю, что он крут), но на сайте Racket увидел рекоммендацию взять "How to Design Programs, Second Edition". Решил пока что с неё и начать, но что-то мне подсказало, что на английском будет учить крайне сложно, и всё-таки лучше начать учить по-русски.

Собственно, вопросы:
1. что делать?
2. есть ли "How to Design Programs" на русском?
3. насколько сумасшедшей считается идея попробовать перевести эту книгу на русский постепенно?

Спасибо!

Вообще говоря, вот этот саблаймо-подобный алгоритм поиска явно как-то можно улучшить, т.к. до сих пор, ища по проекту только что, например, файл "terrain.py", оно умудряется заматчить кучу хлама, где таки находится t.*e.*r.*r.*a.*i.*n. Ну, вы поняли. Интересно на досуге подумать о хороших решениях.

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

Драйвер редиса возвращает `Redis (Either Reply a)`. При операции `HGET` возвращает, соответственно, `Redis (Either Reply (Maybe ByteString))`, типа значения по ключу может и не быть. Программист для упрощения пишет сначала специальную функцию `redis'`, которая заворачивает ответ редиса в EitherT-based монаду, чтоб соединять подобные вычисления и возвращать первую неудачу:

```
newtype Redis' a = Redis' (EitherT Redis.Reply Redis.Redis a) deriving (MonadIO)
instance Monad Redis' where
    return = Redis' . EitherT . return . Right
    (Redis' m) >>= f = Redis' $ m >>= \rv -> unwrapRedis' $ f rv
redis' = Redis' . EitherT
```

Таким образом, теперь, если вы получаете ответ `Redis (Either Reply a)`, вы его преобразуете в

```
Redis' (EitherT Reply Redis a)
```

и можете соединять подобные вычисления в do-блоке типа:

```
do
    res <- redis' $ Redis.hget foo bar
    res2 <- redis' $ Redis.hget baz zab
```

и вычисление остановится на первом возврате ошибки.

Далее. Программисту необходимо по кучке значений сделать `HGET` и вернуть это как-то внутри кортежа, поскольку мы внутри новой монады `Redis'` -- завернуть результат в неё. В случае, если значения хоть по одному ключу не существует, хочется вернуть `Nothing` для всех. Потому создаётся новая монада:

```
newtype HashFields a = HashFields (MaybeT Redis' a)
    deriving (Functor, Monad)
instance Applicative HashFields where
    pure = return
    (<*>) = ap
```

описывающая вычисления типа `Redis'`, которые могут вернуть неудачу. Пишется новая функция

```
hashField = HashFields . MaybeT . redis'
```

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

```
getField :: ByteString -- ^ Key
         -> ByteString -- ^ Hash field name
         -> HashFields String
getField key field = fmap toString $ hashField $ Redis.hget key field
```

Также напишем функцию, которая "запустит" наше вычисление:

```
getRedisFields :: forall a. HashFields a -> Redis' (Maybe a)
getRedisFields (HashFields f) = runMaybeT f
```

И теперь лёгким движением руки мы можем сделать что-то вроде:

```
getRedisFields ((,,,,,) <$>
    getField k "foo" <*>
    getField k "bar" <*>
    getField k "baz" <*>
    getField k "zab" <*>
    getField k "rab" <*>
    getField k "oof")
```

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

Кстати, официально признаю идею перенести Ctrl на капслок очень удачной. Действительно теперь могу сказать, что стало лучше, причем не только в емаксе, а в файрфоксах и прочих местах тоже.

Мда. Докер кеширует как-то очень странно, чего-то я не понимаю. Один и тот же кусок вместо чтения из кеша заново пересобирает иногда (но не всегда). В связи с этим придётся "коммитить образ" ghc/cabal и дальше с него начинать. В общем, штука очень крутая, но до конца не ясны все плюсы и минусы в плане полезных юз-кейсов.