metaclass: (Default)
metaclass ([personal profile] metaclass) wrote2009-08-11 10:19 am

А вот теперь пример безумия

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

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

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

[identity profile] metaclass.livejournal.com 2009-08-11 01:23 pm (UTC)(link)
Я думаю, что если на Haskell писать реальный проект, которому нужны логгеры - привлекательность резко потеряется, т.к. логгирование это априори побочные эффекты, а для них нужно тащить за собой IO :)

[identity profile] migmit.vox.com (from livejournal.com) 2009-08-11 06:34 pm (UTC)(link)
А Writer-а не хватит ли?

[identity profile] metaclass.livejournal.com 2009-08-11 06:39 pm (UTC)(link)
Логгинг априори означает надежность, т.е. "мы хотим видеть последние сообщения перед тем, как сервер самоуничтожился". А надежность означает, что вызов лога за минимальное время попадает в persistent storage. Что очевидно, побочный эффект. А, насколько я понимаю, Writer будет лог накапливать где-то в себе, если он функционально чистый.

[identity profile] mibori.livejournal.com 2009-08-11 06:52 pm (UTC)(link)
Уточню малость.
Он хотел сказать WriterT w IO a :)

[identity profile] migmit.vox.com (from livejournal.com) 2009-08-11 06:57 pm (UTC)(link)
Нет, не хотел.

[identity profile] mibori.livejournal.com 2009-08-11 07:09 pm (UTC)(link)
А как еще сочетать IO и Writer?

[identity profile] migmit.vox.com (from livejournal.com) 2009-08-11 07:15 pm (UTC)(link)
Point в том, чтобы их НЕ совмещать.

[identity profile] migmit.vox.com (from livejournal.com) 2009-08-11 07:01 pm (UTC)(link)
Ой, не факт. По ленивости может получиться совсем даже наоборот. Не уверен, правда.

[identity profile] migmit.vox.com (from livejournal.com) 2009-08-11 07:15 pm (UTC)(link)
Что-нибудь в таком стиле (первое пришедшее в голову):
newtype LogM a = LogM (forall b. (String -> b -> b) -> b -> (a, b))
log :: String -> LogM ()
log s = LogM $ \f b -> ((), f s b)
instance Monad LogM where
  return x = LogM $ const $ (,) x
  LogM l >>= h = LogM $ \f b -> let {(a, b') = l f b; LogM l' = h a} in l' f b'
runLog :: File -> LogM a -> IO a
runLog file (LogM l) =
  let (a, io) = l (\s io -> io >> writeStringToFile file s) (return ())
  in io >> return a

[identity profile] migmit.vox.com (from livejournal.com) 2009-08-11 07:20 pm (UTC)(link)
loggedAction =
  do log "I'm going to do something very unsafe"
     a <- veryUnsafeFFIFunction
     log "Unsafe place passed, everything OK"
     b <- relativelySafeFFIFunction a
     log "Just to make sure"
main = runLog (openFile "log.txt") loggedAction

Ну и в log.txt потом (наверное) прочитаем:
I'm going to do something very unsafe
Unsafe place passed, everything OK

[identity profile] metaclass.livejournal.com 2009-08-11 07:25 pm (UTC)(link)
А где операция закрытия файла, что-то я ее не наблюдаю явно?

[identity profile] migmit.vox.com (from livejournal.com) 2009-08-11 07:36 pm (UTC)(link)
Ну ёлки, это же так, пример, причём немного юмористический.

[identity profile] permea-kra.livejournal.com 2009-08-11 10:37 pm (UTC)(link)
Для долгих вычислений - скорее нет, чем да.

[identity profile] zelych.livejournal.com 2009-08-12 01:44 pm (UTC)(link)
А вот интересно, о каких событиях обычно в лог пишут?
Если, к примеру, взять апач: пришёл запрос, ушёл запрос, кончилась память.
Все они и так в IO, нет никаких проблем.

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

[identity profile] metaclass.livejournal.com 2009-08-12 02:01 pm (UTC)(link)
Вот для отладки оных вычислений логи бывают и нужны. Когда там ошибка возникает на миллиардной итерации.

[identity profile] zelych.livejournal.com 2009-08-12 02:08 pm (UTC)(link)
Для отладки "большой функции со сложными вычислениями" (если она чистая) достаточно знать только что пришло ей на вход. Дальше можно её отладчиком, или на части поделить, или trace'ов напихать.

А откуда берётся то, что у неё на входе? Это либо пакеты из сети, либо файлы с диска, лбо пользовательский ввод, либо последствия многопоточности.
Всё это выполняется в IO.
Т.е. перед выполнением "больших сложных вычислений" мы из IO естественным образом можем положить в лог всё, что нам потребуется для отладки.