1. Куча / Говнокод #10040

    +99

    1. 01
    2. 02
    3. 03
    4. 04
    5. 05
    6. 06
    7. 07
    8. 08
    9. 09
    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
    import Text.Parsec
    import Control.Monad
    
    romanToArabic :: String -> Either ParseError Integer
    romanToArabic = parse (genParser (Nothing : Nothing : map Just romans)) "" where
    
        romans = [('M', 1000), ('D', 500), ('C', 100),
                  ('L', 50), ('X', 10), ('V', 5), ('I', 1)]
    
        genParser [_] = eof >> return 0
        genParser (ten : five : one : rest) = state1 where
    
            state1 = choice [on one state2, on five state3, next]
            state2 = choice [on (sub2 five one) next, on (sub2 ten one) next,
                             on one state5, next]
            state3 = choice [on one state4, next]
            state4 = choice [on one state5, next]
            state5 = choice [on one next, next]
            next = genParser (one : rest)
    
            on Nothing _ = fail ""
            on (Just (ch, val)) nextNode = char ch >> nextNode >>= return . (+val)
    
            sub2 = liftM2 $ \(ch1, val1) (ch2, val2) -> (ch1, val1-2*val2)

    Кучка в ответ на http://govnokod.ru/9995#comment136058

    > с другой стороны раз хаскель, то хотелось бы, например:
    > *Main> romanToArabic "LC"
    > Left (line 1, column 2):
    > unexpected 'C'
    > expecting "X", "IX", "IV", "V", "I" or end of input

    Запостил: bormand, 25 Апреля 2012

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

    • Всё больше Чистых Языков стало появляться на говнокодике. ^_^
      Ответить
    • Я не знаю, что делает >>, но разве nextNode >>= return . (+val) и nextNode . (+) val не эквивалентны? Хз, тут еще пойди угадай у чего приоритет выше...
      Ответить
      • . - композиция ф-ций
        >>= - извлечь результат I/O action'а, передать дальше

        >> - тоже что и >>=, но результат игнорируется

        Приоритет выше у композиции ф-ций.
        Ответить
        • Эти я как раз знаю, я не знаю, что делает >>.
          Ответить
        • А, блин Г-маил тупо убрал вторую строчку - видно подумал, что цитата.
          Тогда я пас, я не могу разгадать, что тут написано :)
          Ответить
          • Вернее, на самом деле есть всего два варианта, и можно угадать, что происходит, если знать, что делает "char ch":
            1. (+ ("char ch" ("return" ("Just" (x y)))) y)
            2. (+ ("return" ("char ch" ("Just" (x y)))) y)
            Ответить
    • Можно обойтись всего одним состоянием (парсить повторяющиеся):

      import Text.Parsec
      import Control.Monad ( guard )
      
      
      type Roman = Parsec String Int Int
      
      arabic :: Char -> Int
      arabic 'M' = 1000
      arabic 'D' = 500
      arabic 'C' = 100
      arabic 'L' = 50
      arabic 'X' = 10
      arabic 'V' = 5
      arabic 'I' = 1
      arabic  c  = error $ "unknown Roman digit: " ++ [c]
      
      
      romanToArabic :: String -> Either ParseError Int
      romanToArabic = runP parseRoman 0 ""
      
      parseRoman :: Roman
      parseRoman = do
        mmm <- parseMany3 'M'
        mdc <- parseOrder 'M' 'D' 'C'
        clx <- parseOrder 'C' 'L' 'X'
        xvi <- parseOrder 'X' 'V' 'I'
        eof
        return $ mmm + mdc + clx + xvi
      
      
      parseOrder :: Char -> Char -> Char -> Roman
      parseOrder ten five one =
             one `before` ten
         <|> one `before` five
         <|> (char five >> (arabic five +) `fmap` parseMany3 one)
         <|> parseMany3 one
      
          where a `before` b = try (string [a,b])
                            >> return (arabic b - arabic a)
      
      
      parseMany3 :: Char -> Roman
      parseMany3 c = do
        putState 0
        skipMany $ do st <- getState
                      guard $ st < 3
                      modifyState (+1)
                      char c
        (arabic c *) `fmap` getState
      Ответить
      • <|>
        <|>
        <|>

        спайдермен.
        Ответить
        • Или хаскеллист примеряет двууголку. Вид сверху.
          Ответить
      • Этот код понятнее чем мой, хотя и длиннее :)

        Кстати, состояние, изменяемое putState, доступно в течении всей работы парсера?
        Ответить
        • Длиннее, правда. (Хотя если arabic переписать и убрать аннотации - наверное будет сравнимо.)
          Да, состояние доступно везде: там runP применяется и начальное 0 передается - не очень хорошо :).

          С другой стороны "парсить не больше 3" сводится к "небольше 2" - можно и переписать.
          Ответить
          • Ну тогда в моем коде можно поменять ужас в виде nextNode >>= return . (+val) на modifyState (+val) >> nextNode.
            Ответить
            • В этом случае состояние - оверхэд (у меня, кстати тоже).
              Может просто переписать дле строчки с on в одно 4-строчное определение? :
              do let Just .. = .. ; .. ; .. <- nextCode ; return ..
              Ответить
              • возможно, но уже лень :)
                Ответить
                • Применение монад плохо сказывается на оптимизации кода, тк свобода у компилятора уходит?
                  Ответить
    • >parseRoman
      parseBormand
      Ответить

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