Хламидомонада / Говнокод #11976 Ссылка на оригинал

0

  1. 1
  2. 2
  3. 3
  4. 4
  5. 5
  6. 6
  7. 7
  8. 8
  9. 9
  10. 10
  11. 11
  12. 12
  13. 13
  14. 14
  15. 15
  16. 16
  17. 17
  18. 18
  19. 19
  20. 20
  21. 21
  22. 22
  23. 23
  24. 24
  25. 25
  26. 26
  27. 27
  28. 28
  29. 29
  30. 30
  31. 31
  32. 32
  33. 33
  34. 34
  35. 35
  36. 36
  37. 37
  38. 38
  39. 39
  40. 40
  41. 41
  42. 42
  43. 43
  44. 44
  45. 45
  46. 46
  47. 47
  48. 48
  49. 49
  50. 50
  51. 51
  52. 52
  53. 53
  54. 54
  55. 55
  56. 56
  57. 57
  58. 58
  59. 59
  60. 60
  61. 61
  62. 62
  63. 63
  64. 64
  65. 65
  66. 66
  67. 67
  68. 68
  69. 69
  70. 70
  71. 71
  72. 72
  73. 73
  74. 74
  75. 75
{-# LANGUAGE ExistentialQuantification,
             DeriveDataTypeable,
             PatternSignatures #-}

import Data.Typeable
import Control.Concurrent
import Control.Concurrent.MVar
import Control.Concurrent.Chan

-- Core data types

data Message = forall t . Typeable t => Message t | StopMessage
    deriving Typeable

data Handler = forall t . Typeable t => Handler (t -> IO ())


-- Worker thread

data Worker = Worker (Chan Message) (MVar ())

workerThread :: [Handler] -> Chan Message -> MVar () -> IO ()
workerThread handlers chan finish = loop where
    loop = do
        message <- readChan chan
        case message of
            StopMessage -> putMVar finish ()
            Message val -> do
                foldr (tryHandler val) (putStrLn "Unhandled message") handlers
                loop
    tryHandler val (Handler h) rest = maybe rest h (cast val)

startWorker :: [Handler] -> IO Worker
startWorker handlers = do
    chan <- newChan
    finish <- newEmptyMVar
    forkIO (workerThread handlers chan finish)
    return $ Worker chan finish

send :: Typeable m => Worker -> m -> IO ()
send (Worker chan _) message = do
    writeChan chan $ Message message

stopWorker :: Worker -> IO ()
stopWorker (Worker chan finish) = do
    writeChan chan $ StopMessage
    takeMVar finish


-- Some tests

data Test = Test Bool String deriving Typeable

intHandler :: Int -> IO ()
intHandler val = putStrLn $ "Int: " ++ show (val * 2)

strHandler :: String -> IO ()
strHandler val = putStrLn $ "String: " ++ reverse val

testHandler :: Test -> IO ()
testHandler (Test b s) = putStrLn $ "Test: " ++ show b ++ " " ++ show s

main = do
    w <- startWorker [
        Handler intHandler,
        Handler (\(val::Char) -> putStrLn $ "Char: " ++ show val),
        Handler strHandler,
        Handler testHandler]
    send w (5::Int)
    send w False
    send w 'a'
    send w "foo"
    send w (Test True "bar")
    stopWorker w
    putStrLn "Finished!"

Вот такая вот портянка была написана под влиянием дискуссии с HaskellGovno http://govnokod.ru/11968, и недавней его просьбой рассказать об общении потоков в хаскеле.

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

P.S. Для неимеющих хаскеля, но желающих посмотреть на работу кода: http://ideone.com/OMVamc.

Запостил: bormand bormand, (Updated )

Комментарии (43) RSS

  • >портянка была написана под влиянием HaskellGovno
    Очень красиво. 🙂 Декларативно. А как этот паттерн называется? Планировщик на основе статически типизированных сообщений?
    Ответить
  • Я у них поел, но выглядит просто круто.
    Ответить
  • Получается Int и прочие стандартные типы по дефолту отнаследованны от интерфейса (Typeable a => a)... Интересно, оно переголову даёт какую-нибудь?
    Ответить
    • Не отнаследованы от Typeable, а принадлежат Typeable. Если мне не изменяет память, оверхед там только при использовании типов данных с forall, в остальных случаях компилятору и так все ясно.
      Ответить
  • Это ты написал какой-то конвейер с нелимитированной очередью-списком, которая типа канал.
    А хендлеры - это вновь изобретенный полиморфизм или же мультиметоды, если хотите.
    >StopMessage -> putMVar finish ()
    А без отравленных сообщений никак нельзя? Недолюбливаю я эти пилюли.

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

      > А без отравленных сообщений никак нельзя? Недолюбливаю я эти пилюли.
      Поясните плиз, что не так со StopMessage?

      > я такую же хреновину в императивном стиле напишу за 15 минут с библиотечной очередью
      Да я не спорю ;). На питоне всяко и за 5 можно управиться.
      Ответить
      • >Поясните плиз, что не так со StopMessage?
        Да как-то некошерно в очереди с данными передавать управляющие конвеером сообщения.
        volatile boolean terminated=false;
        Ответить
        • > Да как-то некошерно в очереди с данными передавать управляющие конвеером сообщения.
          > volatile boolean terminated=false;
          Так с этим булом потом начинаются проблемы - надо одновременно опрашивать и бул и очередь. Как это сделать в хаскеле - я х.з.

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

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

            PS. Херня какая-то с говнокодом. Сессии на главной нету, а на остальных есть.
            Ответить
            • > Если потребителей много - не проще.
              Как вариант - если у нас N воркеров - вбросить N сообщений об остановке. Каждый получит ровно по одному. Минус способа - надо знать сколько именно запущено воркеров.
              Ответить
              • >Как вариант - если у нас N воркеров - вбросить N сообщений об остановке.
                Ну ведь потому и костыль. В данном случае оно вылазит наружу во всей красе.
                Говно всплывает к верху, так сказать.
                Переменная, а зачастую какой-то енум с состояниями INIT,RUN,STOP,FAIL гораздо лучше.
                Ответить
                • Напоминает Бивиса и Баттхеда
                  - Баттхед, ты слышал, он сказал: "прибор!".
                  - А еще он сказал "канал"! Гы-гы-гы.
                  Ответить
                  • Как-то раз, в одном из трамваев я увидел надпись "давайте уедем жить в Питер", выцарапанную на спинке кресла каким-то отчаянным романтиком. Наверно, это был тарас Б.
                    Ответить
      • >Да я не спорю
        тогда непонятно в чем крутота хацкила, если всё то же, но только хуёвей.

        Он по идее должен сам как-то всё асспараллелить и предоставить какую-то сверхудобную реализацию producer-consumer отношений.
        Ответить
    • >Ничего сверхгодного в вашем бомжественном хацкиле нету, я такую же хреновину в императивном стиле напишу за 15 минут

      Я расскажу тебе свою историю.

      Я учился в университете, по специальности программист. Да, я не был в группе самым одарённым, но я пытался что-то делать. Нам преподавали C++. Я не очень это всё понимал. Мои одногруппники были не очень хорошими людьми, и всегда не воспринимали меня и даже ущемляли. Преподы тоже не упускали своего и говорили, что только тупые не могут понять C++. Я не был тупой, я просто не понимал зачем всё это нужно?

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

      И вдруг я услышал разговор двух молодых парней, которые выходили из новой машины, они говорили про программирование. Они были классно одеты. У них было много денег. Я хотел быть ими. Я подошёл к ним и спросил:
      — Как мне стать таким как Вы?
      Они улыбнулись и сказали: “Пошли с нами”.
      Ответить
      • Мы зашли в ближайшее кафе, один из них достал ноутбук и показал его — Haskell. Я по-настоящему понял. Я влюбился. Я был счастлив. Я пошёл домой, я прочитал haskellwiki, я накачал книг с amazon.com, я начал читать. Да я уже не ходил на занятия, мне они были уже не нужны. Потом мне позвонили из деканата и сказали, что отчислят меня, если я не сдам курсовую. Мне было наплевать, что меня отчислят, но курсовой, я его сдам, ведь у меня есть новое знание.

        Когда я пришёл на защиту, то там собралась вся группа.

        Они подходили к компьютерам и демонстрировали применение паттернов и шаблонов, наследование и прочее, всё что на самом деле не нужно.

        Потом настала моя очередь. Я встал и медленно шёл. Они смеялись и кричали — что не написал видать?

        Когда я показал этот код, который делал одной строчкой то, что у них было в 25 классах, они замолчали. Я встал и ушёл.

        Говорят препод ушёл с работы из-за того, что свихнулся, он не мог поверить что его C++ не нужен.

        Я теперь иногда телефоны своих одногруппников в газете объявлений, где они готовы работать за еду. Но мне пофиг, я знаю Haskell, что приносит мне тысячи долларов.
        Ответить
        • 1. Когда вижу портянку в полтора экрана - сразу ясно что это не твой текст.
          2. Тухло, ведь я уже читал эту пасту.
          3. Она неуместна - в примере 50 строк потрачено на конвейер.
          Ответить
          • > 1. Когда вижу портянку в полтора экрана - сразу ясно что это не твой текст.
            +

            > 2. Тухло, ведь я уже читал эту пасту.
            +

            > 3. Она неуместна - в примере 50 строк потрачено на конвейер.
            Ну не на сам конвейер, в качестве которого тут использовался готовый Chan, а на тред, который этот конвейер использует.
            Ответить
          • Я пасту не видел, она доставила, я плюсанул. Твой ответ тоже.
            Ответить
            • у меня тоже есть история:

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

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

              - это все очень хорошо, но для нашей программы этого всего не нужно.
              Ответить
  • Кстати, понял, почему работает фишка с типизацией хендлеров в контейнере?
    Ответить
  • У меня нубский вопрос: А вот на Хокаге.хаскел.орг или на каких-то других сайах с документацией часто упоминается какие-то правила laws. Что это означает и как это выражается в коде Хаскеля? Почему для этого отдельный термин используют laws (законы)?
    Ответить
    • Это же законы. Как комутативность и асоциативность в матане.
      Ответить
      • Они в коде стандартной библиотеки как-то выражаются? Например проверяются ассертами?
        Ответить
  • А что делать тем, у кого нет хачкеля и кто не желает видеть ни результата работы кода, ни хачкеля?
    Ответить
  • >недавней просьбой HaskellGovno рассказать об общении потоков в хаскеле.
    Спасибо. 🙂
    Ответить
  • Какой нормальный человек в здравом разуме будет писать на "Haskell"?
    Ответить
      • Заметил, что только вы со "chayt" (и ещё пара чьих-то фаек) пишите говнокоды на нём
        Ответить
          • Кстати, запиши, пожалуйста, функцию :: (Double, Double) -> (Double, Double) -> Double, вычисляющую расстояние между двумя точками на плоскости по классической формуле так, чтобы в записи тела функции не было скобок, кроме, возможно, скобок, превращающих инфиксные функции в префиксные.
            Ответить
            • Не знаю, как это делается на хаскеле, но знаю как на J:
              dist =: [:%:@+/[:*:-
                 NB. или
                 require 'primitives'
                 dist =: cap sqrt atop plus insert cap square minus
                 2 3 dist 4 6
              3.60555
                 2 3 dist 2 3
              0
                 2 2 dist 6 2
              4
              Ответить
              • dist =: [: %:@+/ [: *:@+.-
                   NB. или
                   dist =: cap sqrt atop plus insert cap square atop realimaginary minus
                   2j3 dist 3j2
                1.41421
                   2j3 dist 2j3
                0
                   2j2 dist 2j4
                2
                Спасибо, я кончел.
                Ответить
            • Это на степике такая задача есть? Специальная олимпиада объявляется открытой?
              import Data.STRef
              import Control.Monad.ST
              import Data.Complex
              
              -- Level: Beginner
              -- Well, there are no parantheses...
              dist1 x y = let dx = fst x - fst y; dy = snd x - snd y in sqrt $ dx^2 + dy^2
              
              -- Level: Math geek
              -- Ha, I know complex numbers
              dist2 x y = magnitude $ uncurry (:+) x - uncurry (:+) y
              
              -- Level: Former imperative programmer
              dist3 x y = runST $ do
                ref <- newSTRef $ (^2) $ fst x - fst y
                modifySTRef ref $ (+) $ (^2) $ snd x - snd y
                sqrt <$> readSTRef ref
              P.S. придумал забавный способ сконвертировать пару в список, но не придумал, как его красиво использовать на двух парах, чтобы заюзать sqrt . sum . map (^2) . zipWith (-)
              :t uncurry (:) . fmap pure
              uncurry (:) . fmap pure :: (a, a) -> [a]
              Ответить

Добавить комментарий

Из-за тебя ушел bormand, guest!

    А не использовать ли нам bbcode?


    8