LINUX.ORG.RU

Сообщения yoghurt

 

Live Programming In Modern Smalltalk

Форум — Development

Всем привет,

Делюсь курсом, который я организовал и провёл для своей команды и коллег. Вероятно кому-то будет интересно.

Цель курса – развить практические навыки работы в среде Смолток, в первую очередь чтобы она не казалась чем-то инопланетным – и чтобы знать, с какой стороны подойти к Смолтоку при самостоятельном обучении.

Материалы | Записи занятий

 , ,

yoghurt ()

Mozilla объявляет новые ценности и увольняет 250 сотрудников

Новости — Mozilla
Группа Mozilla

Mozilla Corporation в своем блоге объявила о значительной реструктуризации и связанным с этим увольнением 250 сотрудников.

Причинами данного решения, по словам CEO организации Митчелл Бейкер, являются финансовые проблемы, связанные с пандемией COVID-19, и изменения в планах и стратегии компании.

Выбранная же стратегия ориентируется на пять основных принципов:

  1. Новый фокус на продуктах. Утверждается, что их у организации будет несколько.
  2. Новый способ мышления (англ. mindset). Ожидается переход от консервативной/закрытой позиции к более открытой и агрессивной (вероятно, в плане стандартов – прим. перев.).
  3. Новый фокус на технологии. Предполагается выход за пределы «традиционной веб-технологии», в качестве примера приводится Bytecode Alliance.
  4. Новый фокус на сообществе, большая открытость к разным проявляемым инициативам в построении его (сообщества) видения Интернета.
  5. Новый фокус на экономике и рассмотрение иных бизнес-моделей.

>>> Подробности

 ,

yoghurt ()

10 лет, как забанили Саныча

Форум — Talks

Было в июне-ли, но кто уж вспомнит.

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

Помним, любим.

Это называется «инфлюенс»

 

yoghurt ()

Летняя стажировка в Intel - 2019

Форум — Job

Всем привет!

Открыта регистрация для студентов в ежегодную летнюю школу Intel в Нижнем Новгороде. Ещё есть время присмотреться к задачам и выбрать подходящую (до 4го мая). Далее следуют отбор и собственно сама стажировка.

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

Есть так же неиллюзорная возможность свои наработки законтрибьютить в open source - OpenCV как ярчайший пример. Ну и, разумеется, всё под онтопиком.

Если ты - нижегородский студент-плюсист (ну или питонист), чего же ты ждешь, регистрируйся скорее!

 ,

yoghurt ()

Bzip2 потерялся

Форум — Talks

Не знаю, было тут или нет, но:

https://lwn.net/Articles/762264/

A search for «bzip2 source» returns bzip.org as the first three results. But it would seem that the owner of this domain has let it go, and it is now parked and running ads. So we no longer have an official home for bzip2. If a new repository or tarball does turn up at that domain, it should be looked at closely before being trusted

 ,

yoghurt ()

Обработка изображений на AWK

Галерея — Скриншоты

AWK внезапно оказался неплохим языком для обработки изображений — весь код уложился где-то в 180 строчек, можно посмотреть здесь.

Реализован алгоритм определения границ Дж. Кэнни, который, как известно, состоит из нескольких этапов. Каждый этап был вынесен в отдельный скрипт awk, и затем всё вместе собрано пайпами. Получаем труЪ потоковую обработку — эдакий OpenCL «за 40 лет до».

На скриншоте в терминале показан сам конвеер и как с ним справляются разные реализации awk. Моя в конкурсе пока не участвует - сыровата ещё :-) Собственно, для сравнения всё и задумывалось (бенчмаркаться на простых текстах поднадоело).

В остальном — дефолт, дебиан, гном3, ещё и вейленд, как выяснилось.

>>> Просмотр (1366x768, 671 Kb)

 

yoghurt ()

Программа, которая ответит на вопрос «почему»

Форум — Development

Результат нескольких лет труда одного паренька: https://github.com/andyjko/whyline

В действии: https://www.youtube.com/watch?v=t6gVZ-qZ4sI

Для Ъ - программа анализирует байткод и записывает трассу Java-приложения таким образом, что потом можно его выполнение крутить взад-вперед и инспектировать состояние переменных - в т.ч. понимать, каким образом мы в данном месте получили именно это значение.

Переворот в отладке? Какому технологическому стеку (помимо java/jvm в данном случае) ещё подвластно подобное? Теоретически, на Smalltalk вполне себе можно замутить. Или на JavaScript. Ещё?

 

yoghurt ()

A decade of wasted cores

Форум — Development

Планировщик линукса, говорят, не совершенен

http://www.ece.ubc.ca/~sasha/papers/eurosys16-final29.pdf

https://github.com/jplozi/wastedcores

 ,

yoghurt ()

bash и -bash

Форум — General

Открываю, значит, терминал:

$ echo "$0"
bash

Теперь то же самое в tmux:

$ echo "$0"
-bash

Что это и почему это? В итоге не работает скрипт, будучи запущен из tmux, который использует внутри readlink -f "$0".

В гугле не нашёл :( Да, да, 5 звёзд и все дела.

 , ,

yoghurt ()

?ELPA для пенсионеров

Форум — General

День добрый,

В новом 2016м году решил приобщиться к стильному-модному и попробовать устанавливать пакеты в свой Emacs пакетным менеджером.

Начать пробовать решил с magit (который тоже решил освоить в новом 2016м году), всё сделал по инструкции и вот незадача - какому-то пакету, кажется, with-editor, нужен Emacs 24.4, а у меня только Emacs 24.3.

Что благородные доны делают в таком случае? Можно ли как-то выбрать версию пакета в мельпе/ельпе/etc, чтобы поставить всё в срезе, например, «лето-2014»? Сам Emacs ради этого обновлять не очень хочу, быстрого способа в интернетах не нагуглил.

 ,

yoghurt ()

Тут эксперты обсуждают возможность перехода на СПО

Форум — Talks

 

yoghurt ()

PharoVX

Галерея — Скриншоты

Есть такой стандарт - OpenVX, который определяет набор аппаратно-ускоренных функций компьютерного зрения, и теперь вот у моего любимого Smalltalk есть к нему биндинг.

Работает он, пока что, только с референсной реализацией от Khronos, но играться уже можно. Почти все функции поддерживаются.

Написано в основном во время пребывания на конференции ESUG 2015, вот как-то так.

Страничка проекта

>>> Просмотр (1366x768, 565 Kb)

 , ,

yoghurt ()

Умер диск?

Форум — Linux-hardware

Раскрываю, значит, сегодня из саспенда (оставил на 5 минут) свой Thinkpad x230i, он на ls в ~ говорит IO error, выключаю кнопкой, включаю, и всё.

Диск говорит «клац-клац-клац» (он обычный НЖМД, ну не было в магазине варианта с SSD), ничего долго не происходит, потом Леновошный биос (или кто там) пишет на экран «2100 Detection error on HDD0 (Main)». Занавес!

Самое ржачное, что это всё случилось на конференции Майкрософт, которая проходила у нас сегодня (на ноуте, естественно, стоял Debian).

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

Завтра поеду за SSD (выбираю между этим и этим - посоветуйте заодно, плиз), но меня интересует такой вопрос - если доктор сказал в морг, значит в морг? Есть ли способ оживить умерший винт вот в таком клиническом случае?

 ,

yoghurt ()

Научите правильно готовить монады через CPS

Форум — Development

Тут будет много букв, я морально готовился месяц, поэтому за объем заранее извиняйте. Сразу скажу - на ассемблерах я не писатель, и цель треда - не обсуждение дизайнерских решений, а производительность монад. Суть всплывёт ближе к концу (я надеюсь).

Представим, что мы моделируем некий процессор, у которого есть простой набор инструкций. С инструкций и начнем:

data Register = R1 | R2 | R3 | R4 | R5 | R6
                deriving (Show)
     
data Operator = ADD | SUB | MUL | DIV
              | LESS | EQUAL | AND | OR | NOT
              | MOV
              | JMT | JMF | JMP
              | PRN | NOP
                deriving (Show)

class OperandClass a where
   toOperand :: a -> Operand

instance OperandClass Register where
   toOperand = R

instance OperandClass Operand where
   toOperand = id

instance OperandClass () where
   toOperand _ = N

data Operand = R !Register | V !Double | I !Int | N
               deriving (Show)

type Instruction = (Operator, Operand, Operand) 

Иными словами, всё очень просто: инструкция - это кортеж оператора и операндов, операндом могут быть регистр, значение, или ничего.

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

-- | Monad for programming instructions 

type ASM a = State [Instruction] a

compile :: ASM a -> [Instruction]
compile c = execState c []

op :: (OperandClass s, OperandClass d) => Operator -> s -> d -> ASM ()
op cmd src dst = modify $ \s -> s ++ [(cmd, toOperand src, toOperand dst)]

pos :: ASM Int
pos = liftM length get

nop :: ASM Int
nop = do { p <- pos; op NOP () (); return p}

putOp :: (OperandClass s, OperandClass d) => Int -> Operator -> s -> d -> ASM ()
putOp p cmd src dst = do
    let instr = (cmd, toOperand src, toOperand dst)
    (before,after) <- liftM (splitAt p) get 
    put $ before ++ instr : tail after

Тут, опять же, ничего сложного. Для наглядности, немного забегая вперед, приведу пример кода на этом «ассемблере». Данный код считает квадратный корень заданного числа методом Герона с заданным приближением (числом шагов):

-- | Heron's method to calculate square root
-- Inputs:  r1 - value to calculate square root from
--          r2 - number of iterations
-- Outputs: r6 - output value
heron :: ASM ()
heron = do
   op MOV (V 1) R5
   op MOV (V 0) R3
   iterStart <- pos
   op MOV R3 R4
   op EQUAL R2 R4
   ifFalse <- nop
   op MOV R1 R6
   op DIV R5 R6
   op ADD R5 R6
   op MUL (V 0.5) R6
   op MOV R6 R5
   op ADD (V 1) R3
   op JMP (I iterStart) ()
   loopEnd <- pos
   putOp ifFalse JMT R4 (I loopEnd)
   op PRN R6 ()

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

Идём дальше. Чтобы это всё выполнять, нужна ещё одна монада:

-- | Monad for executing instructions

data Registers = Registers
               { r1 :: !Double
               , r2 :: !Double
               , r3 :: !Double
               , r4 :: !Double
               , r5 :: !Double
               , r6 :: !Double
               } deriving (Show)

initialRs :: Registers
{-# INLINE initialRs #-}
initialRs = Registers
            { r1 = 0
            , r2 = 0
            , r3 = 0
            , r4 = 0
            , r5 = 0
            , r6 = 0
            }

type CPU a = StateT Registers IO a

execute ::Registers -> [Instruction] -> IO Registers
execute rs code = execStateT (exec code) rs
  where
   {-# INLINE exec #-}
   exec ((JMP, I pos, _    ):is) = {-# SCC "JMP" #-} exec $! drop pos code
   exec ((JMF,   reg, I pos):is) = {-# SCC "JMF" #-} readVal reg >>= \v ->
                                                     exec $! if toBool v
                                                             then is
                                                             else drop pos code
   exec ((JMT,   reg, I pos):is) = {-# SCC "JMT" #-} readVal reg >>= \v ->
                                                     exec $! if toBool v
                                                             then drop pos code
                                                             else is
   exec ((ins,   src,   dst):is) = {-# SCC "OP"  #-} execOP ins src dst >> exec is
   exec []                       = return ()

execOP :: Operator -> Operand -> Operand -> CPU ()
{-# INLINE execOP #-}
execOP ADD   src dst = {-# SCC "ADD"   #-} arith ADD   src dst
execOP SUB   src dst = {-# SCC "SUB"   #-} arith SUB   src dst
execOP MUL   src dst = {-# SCC "MUL"   #-} arith MUL   src dst
execOP DIV   src dst = {-# SCC "DIV"   #-} arith DIV   src dst
execOP LESS  src dst = {-# SCC "LESS"  #-} logic LESS  src dst
execOP EQUAL src dst = {-# SCC "EQUAL" #-} logic EQUAL src dst
execOP AND   src dst = {-# SCC "AND"   #-} logic AND   src dst
execOP OR    src dst = {-# SCC "OR"    #-} logic OR    src dst
execOP NOT   src dst = {-# SCC "NOT"   #-} logic NOT   src dst
execOP MOV   src dst = {-# SCC "MOV"   #-} readVal src >>= \v -> putVal dst $! v
execOP PRN   src _   = {-# SCC "PRN"   #-} readVal src >>= \v -> liftIO $ print v 

arith :: Operator -> Operand -> Operand -> CPU ()
{-# INLINE arith #-}
arith op src dst = do
    v1 <- readVal src
    v2 <- readVal dst
    case op of
       ADD -> putVal dst $! v2 + v1
       SUB -> putVal dst $! v2 - v1
       MUL -> putVal dst $! v2 * v1
       DIV -> putVal dst $! v2 / v1

logic :: Operator -> Operand -> Operand -> CPU ()
{-# INLINE logic #-}
logic op src dst = do
     v1 <- readVal src
     v2 <- readVal dst
     case op of
        LESS  -> putVal dst $! fromBool $ v2 <  v1
        EQUAL -> putVal dst $! fromBool $ v2 == v1
        AND   -> putVal dst $! fromBool $ toBool v1 && toBool v2
        OR    -> putVal dst $! fromBool $ toBool v1 && toBool v2
        NOT   -> putVal dst $! fromBool . not . toBool $ v1

fromBool :: Bool -> Double
{-# INLINE fromBool #-}
fromBool True  = 1
fromBool False = 0

toBool :: Double -> Bool
{-# INLINE toBool #-}
toBool 0 = False
toBool _ = True

readVal :: Operand -> CPU Double
{-# INLINE readVal #-}
readVal (R R1) = gets r1
readVal (R R2) = gets r2
readVal (R R3) = gets r3
readVal (R R4) = gets r4
readVal (R R5) = gets r5
readVal (R R6) = gets r6
readVal (V v)  = return v

putVal :: Operand -> Double -> CPU ()
{-# INLINE putVal #-}
putVal (R R1) v = modify $ \s -> s { r1 = v }
putVal (R R2) v = modify $ \s -> s { r2 = v }
putVal (R R3) v = modify $ \s -> s { r3 = v }
putVal (R R4) v = modify $ \s -> s { r4 = v }
putVal (R R5) v = modify $ \s -> s { r5 = v }
putVal (R R6) v = modify $ \s -> s { r6 = v }

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

Вот и всё!

Полная версия кода доступна на Гитхабе.

С файликом, загруженным в ghci, можно поиграться, например, так:

let h = compile heron
execute (initialRs {r1 = 25, r2 = 4}) h

5.015247601944898 Registers {r1 = 25.0, r2 = 4.0, r3 = 4.0, r4 = 1.0, r5 = 5.015247601944898, r6 = 5.015247601944898}

Но самое важное для меня в данной ситуации - это время, за которое наш компьютер посчитает 10 000 корней. Входные данные и скрипт для запуска есть в репозитории:

$ ghc --make -O3 Asm.hs
$ ./measure.sh

Судя по результатам профайлера, основное время мы таки проводим в нашем процессоре:

COST CENTRE MODULE    %time %alloc

OP          Main       33.6   34.2
PRN         Main       21.4   23.0
READ        Main       16.4   12.8
MOV         Main        8.8   13.2
ADD         Main        5.4    6.7
DIV         Main        3.3    3.7
EQUAL       Main        3.1    3.4
MUL         Main        2.7    3.0
JMT         Main        2.3    0.0
JMP         Main        1.9    0.0


                                                                  individual     inherited
COST CENTRE  MODULE                             no.     entries  %time %alloc   %time %alloc

MAIN         MAIN                                52           0    0.7    0.0   100.0  100.0
 JMT         Main                               113      200000    2.3    0.0    80.7   85.4
  OP         Main                               114     1610000   32.8   33.3    78.3   85.4
   PRN       Main                               121       10000   21.4   23.0    21.4   23.0
   EQUAL     Main                               120      200000    2.7    3.2     2.7    3.2
   JMP       Main                               119      200000    1.9    0.0     1.9    0.0
   MUL       Main                               118      200000    2.7    3.0     2.7    3.0
   ADD       Main                               117      400000    5.4    6.7     5.4    6.7
   DIV       Main                               116      200000    3.3    3.7     3.3    3.7
   MOV       Main                               115      600000    8.2   12.6     8.2   12.6
 EQUAL       Main                               111           0    0.4    0.2     0.4    0.2
 MOV         Main                               108           0    0.6    0.6     0.6    0.6
 OP          Main                               106       40000    0.8    0.9     0.8    0.9
  JMT        Main                               112       10000    0.0    0.0     0.0    0.0
  EQUAL      Main                               110       10000    0.0    0.0     0.0    0.0
  MOV        Main                               107       30000    0.0    0.0     0.0    0.0
 ITER        Main                               105       10000    0.4    0.1     0.4    0.1
 READ        Main                               104           1   16.4   12.8    16.4   12.8
 CAF         Main                               103           0    0.0    0.0     0.0    0.0
  READ       Main                               109           0    0.0    0.0     0.0    0.0

Т.о., исполнение собственно операций (кроме ввода-вывода) занимает около 70% всего времени.

Внимание, суть!. Интересно, как зависит время выполнения от способа организации (или, если хотите, реализации) главной монады в тесте - CPU. Самое простое для начала - попробовать готовые реализации.

Мои результаты:

  • 0.37с - для монады CPU, реализованной поверх пакета transformers
  • 0.39c - для mtl
  • 0.42c - для contstuff

ХаскельВики рекомендует путь джедаев - ручной анроллинг стэков трансформеров и(ли) переход на CPS. Переход на CPS - вообще вещь легендарная, в иных историях успеха оно ускоряет код раз так в 4-8. Проверим:

newtype CPU a = CPU { runCPU :: forall r. Registers -> (a -> Registers -> IO r) -> IO r }

instance Monad CPU where
   return = retCPU
   (>>=)  = bindCPU

instance MonadIO CPU where
   liftIO = lioCPU

retCPU :: a -> CPU a
{-# INLINE retCPU #-}
retCPU x = CPU $ \s k -> k x s

bindCPU :: CPU a -> (a -> CPU b) -> CPU b
{-# INLINE bindCPU #-}
bindCPU (CPU m) f = CPU $ \s0 k -> m s0 $ \a s1 -> runCPU (f a) s1 k

lioCPU :: IO a -> CPU a
{-# INLINE lioCPU #-}
lioCPU f = CPU $ \s k -> f >>= \x -> k x s

get :: CPU Registers
{-# INLINE get #-}
get = CPU $ \s k -> k s s

gets :: (Registers -> a) -> CPU a
{-# INLINE gets #-}
gets f = get >>= \s -> return $! f s

put :: Registers -> CPU ()
{-# INLINE put #-}
put s = CPU $ \_ k -> k () s

modify :: (Registers -> Registers) -> CPU ()
{-# INLINE modify #-}
modify f = get >>= \s -> let s' = f s in put $! s'

Хотите верьте, хотите нет - такой вариант показал результат в 0.41c. Я в печали.

При ручном анроллинге (без CPS):

newtype CPU a = CPU { runCPU :: Registers -> IO (Registers, a) }

instance Monad CPU where
   return = retCPU
   (>>=)  = bindCPU

instance MonadIO CPU where
   liftIO f = CPU $ \s -> f >>= \x -> return (s, x)

retCPU :: a -> CPU a
{-# INLINE retCPU #-}
retCPU x = CPU $ \s -> return (s, x)

bindCPU :: CPU a -> (a -> CPU b) -> CPU b
{-# INLINE bindCPU #-}
bindCPU m f = CPU $ \s -> do (s', a) <- runCPU m s
                             runCPU (f a) s'

get :: CPU Registers
{-# INLINE get #-}
get = CPU $ \s -> return $! (s, s)

gets :: (Registers -> a) -> CPU a
{-# INLINE gets #-}
gets f = get >>= \s -> return $! f s

put :: Registers -> CPU ()
{-# INLINE put #-}
put s = CPU $ \_ -> return (s, ())

modify :: (Registers -> Registers) -> CPU ()
{-# INLINE modify #-}
modify f = get >>= \s -> let s' = f s in put $! s'

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

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

Для вашего удобства, весь код в его текущем состоянии выложен на Гитхабе, каждый вариант в своей ветке.

Простите ещё раз за такую простыню и неровный почерк. Всем любви!

 ,

yoghurt ()

OpenCV Vision Challenge

Новости — Open Source
Группа Open Source

Организация OpenCV Foundation, при поддержке со стороны DARPA и корпорации Intel, открывает конкурс по расширению и дополнению библиотеки OpenCV современными реализациями лидирующих на данный момент алгоритмов компьютерного зрения.

Призовой фонд конкурса составляет $50000. Принимаются работы в 11 направлениях, в том числе:

  • сегментация изображений;
  • определение позы;
  • SLAM;
  • распознавание объектов, лиц, жестов, действий, текста;
  • трэкинг.

Комитет конкурса определит до пяти лучших работ. Участники могут присылать реализации собственных алгоритмов, либо собственные реализации имеющихся опубликованных.

Победители конкурса получат по $1000 за лучшую работу, и дополнительные $7500-$9000, если передадут свой код в OpenCV в виде запроса на слияние (pull-request) под лицензией BSD.

Работы можно присылать до 8 мая 2015г., победители будут названы на ежегодной конференции CVPR 8 июня 2015г.

>>> Подробности

 , , ,

yoghurt ()

Зачем сломали цитирование?

Форум — Linux-org-ru

Верните

Как было

Пожалуйста

UPD: http://i.imgur.com/fuQBmG7.png

yoghurt ()

Haskell, монады, память, и все-все-все

Форум — Development

Есть задача - пройтись по текстовому файлу и найти максимальное число одинаковых последовательно идущих строчек. Задача весьма синтетическая, просто надо продемонстрировать, что

  • Потоково обрабатывается некий объем данных;
  • Есть состояние - надо помнить предыдущую строку в файле при обращении к следующей.

Решение в лоб на IORef-ах (m1.hs):

module Main where

import Data.IORef
import Control.Monad (forM)

main :: IO ()
main = do
   input    <- getContents
   lastLine <- newIORef (Nothing)
   counter  <- newIORef (0)
   result   <- newIORef (0)

   let incr    = modifyIORef counter (\x -> x `seq` x+1)
       reset s = do c <- readIORef counter
                    r <- readIORef result
                    writeIORef result (max c r)
                    writeIORef lastLine (Just s)
                    writeIORef counter  1

   forM (lines input) $ \line -> do
     ml <- readIORef lastLine
     case ml of
       (Just s) -> if s == line then incr else reset line
       Nothing  -> reset line

   r <- readIORef result
   putStrLn $ "Largest subsequence of equal lines: " ++ show r

Более модное решение с трансформером StateT (m2.hs):

{-# LANGUAGE GeneralizedNewtypeDeriving #-}

module Main where

import Control.Monad (forM)
import Control.Monad.State.Strict

data AppContext = AppContext { ctxLastLine :: Maybe String
                             , ctxCounter  :: Integer
                             , ctxResult   :: Integer
                             }

initialContext :: AppContext
initialContext = AppContext { ctxLastLine = Nothing
                            , ctxCounter  = 0
                            , ctxResult   = 0
                            }

newtype App a = App (StateT AppContext IO a)
                deriving (Monad, MonadIO, MonadState AppContext)

runApp (App app) = execStateT app

incr :: App ()
incr = do
   cnt <- gets ctxCounter
   modify $ \s -> s { ctxCounter = cnt+1 }

reset :: String -> App ()
reset l = do
   cnt <- gets ctxCounter
   res <- gets ctxResult
   modify $ \s -> s { ctxLastLine = Just l
                    , ctxCounter  = 1
                    , ctxResult   = max res cnt
                    }

processLine :: String -> App ()
processLine line = do
   ll <- gets ctxLastLine
   case ll of
      (Just s) -> if line == s then incr else reset line
      Nothing  -> reset line

main :: IO ()
main = do
   input <- getContents
   s <- runApp (forM (lines input) processLine) initialContext
   putStrLn $ "Largest subsequence of equal lines: " ++ show (ctxResult s)

Интересно, как поведут себя оба варианта на обработке, скажем, «Улисс» Джойса (txt, 1.6 MB):

[dmatveev@localhost memq]$ ghc --make m1.hs -rtsopts -prof
[1 of 1] Compiling Main             ( m1.hs, m1.o )
Linking m1 ...
[dmatveev@localhost memq]$ ghc --make m2.hs -rtsopts -prof
[1 of 1] Compiling Main             ( m2.hs, m2.o )
Linking m2 ...
[dmatveev@localhost memq]$ du -sh ulysses.txt
1.6M    ulysses.txt
[dmatveev@localhost memq]$ wc -l ulysses.txt
33055 ulysses.txt
[dmatveev@localhost memq]$ time cat ulysses.txt | ./m1 +RTS -hd -i0.001
Largest subsequence of equal lines: 5

real    0m1.599s
user    0m1.577s
sys     0m0.021s
[dmatveev@localhost memq]$ time cat ulysses.txt | ./m2 +RTS -hd -i0.001
Largest subsequence of equal lines: 5

real    0m19.360s
user    0m19.123s
sys     0m0.091s

ШОК! Посмотрим, что там с памятью:

[dmatveev@localhost memq]$ hp2ps -e8in -c m1.hp
[dmatveev@localhost memq]$ hp2ps -e8in -c m2.hp

m1.png, m2.png

Очевидно, что во втором примере что-то течёт, а я что-то глобально упустил.

Вопросы:

  1. ЧЯДНТ?
  2. Как быть?
  3. Как правильно готовить монадические ивентлупы с изменяемым состоянием?

З.Ы. Да, я знаю, что на awk это решается проще и быстрее, суть-то не в этом, а в вопросе №3. Извините за неровный почерк.

 ,

yoghurt ()

MBA

Форум — Talks

Привет, пятничный ЛОР!

Объясни, пожалуйста, популярно - зачем нужен MBA? Я долго пытался понять, что же скрывается за этой таинственной аббревиатурой и какие сакральные знания оно дает, смотрел программы обучения, но всё тщетно.

Ещё слышал мнение, что суть не в знаниях, а в связях. Связи?...

 

yoghurt ()

Планшет по-русски

Форум — Talks

http://lenta.ru/news/2014/07/03/tablet/

Российские специалисты создали планшет для военных, который работает под водой, защищен от пыли и падений, а по характеристикам не уступает другим современным устройствам. Кроме того, гаджет или, как называют его создатели, «рупад», работает на отечественной операционной системе. Об этом сообщает РИА Новости со ссылкой на заместителя генерального директора по развитию Центрального научно-исследовательского института экономики информатики и систем управления (ЦНИИ ЭИСУ) Дмитрия Петрова.

Рудроид?

yoghurt ()

ОС на JS?

Форум — Talks

Всем бояться! http://runtimejs.org/

 

yoghurt ()

RSS подписка на новые темы