Как сделать это лучше? «Может быть, Бул» не выглядит великолепно - PullRequest
3 голосов
/ 07 октября 2019

Прежде всего, я новичок в Haskell, поэтому, если я задаю несколько глупый вопрос, пожалуйста, скажите мне, как я могу сделать лучше. Спасибо:)

Моя задача - получить список строк, соответствующих определенным условиям. Если никакие строки не соответствуют, я хотел бы оценить до Nothing. Поэтому я пишу две функции:

isSpecialLine :: String -> String -> Maybe Bool
isSpecialLine t s = Just $ (("[" ++ t ++ ":") `isPrefixOf` s) && ("]::" `isSuffixOf` s)

getLinesWith :: String -> String -> Maybe [String]
getLinesWith t = filterM (isSpecialLine t) . lines

Этот код работает, но я считаю, что Maybe Bool выглядит немного странно. Эй, это двоичный файл! Это всегда True или False, поэтому значение isSpecialLine всегда будет Just True или Just False. В моем случае это не может быть Nothing!

Но если я изменю тип вывода isSpecialLine на Bool, появится следующая проблема: filterM ожидает Maybe Bool вместо Bool.

Хорошо, я делаю это:

getLinesWith :: String -> String -> Maybe [String]
getLinesWith t = filterM (Just $ isSpecialLine t) . lines

Теперь компилятор жалуется на несовпадающий тип: Maybe (String -> Bool) не соответствует ожидаемому String -> Maybe Bool. Хорошо, довольно разумно. Итак, я:

getLinesWith :: String -> String -> Maybe [String]
getLinesWith t = Just $ filter (isSpecialLine t) . lines

И снова несоответствие типов, на этот раз Maybe (String -> [String]) не String -> Maybe [String]. Какой правильный синтаксис для переноса монады [String] в Maybe?

Ответы [ 3 ]

6 голосов
/ 07 октября 2019

isSpecialLine никогда не производит Nothing, так что это хороший намек на то, что Maybe может и не иметь смысла.

isSpecialLine :: String -> String -> Bool
isSpecialLine t s = (("[" ++ t ++ ":") `isPrefixOf` s) && ("]::" `isSuffixOf` s)

getLinesWith :: String -> String -> [String]
getLinesWith t = filter (isSpecialLine t) . lines
4 голосов
/ 07 октября 2019

Мне кажется, что вам не нужно filterM здесь. Вместо этого вы можете использовать filter :: (a -> Bool) -> [a] -> [a]:

isSpecialLine :: String -> String -> Bool
isSpecialLine t s = isPrefixOf ("[" ++ t ++ ":") s && isSuffixOf "]::" s

getLinesWith :: String -> String -> [String]
getLinesWith t = <b>filter</b> (isSpecialLine t) . lines

Действительно, это вернет список String s, где каждая строка соответствуетisSpecialLine фильтр будет сохранен.

1 голос
/ 07 октября 2019

Вместо использования Maybe и распаковки данных из getLinesWith, например,

getLinesWith :: String -> String -> Maybe [String]
...

getDate :: String -> String -> UTCTime
getDate t s =
    timeFromString
    . filter (/= ' ')
    . getBetweenColons
    . maybe ":01-01-1971:" head $ getLinesWith t s

Я закончил с гораздо более привлекательным (надеюсь) решением без Maybe:

getLinesWith :: String -> String -> [String]
...

getDate :: String -> String -> UTCTime
getDate t s
  | null date = timeFromString "01-01-1971"
  | otherwise = timeFromString
              . filter (/= ' ')
              . getBetweenColons
              . head $ date
  where date = getLinesWith t s    

На самом деле все танцы вокруг Maybe начались, когда GHC пожаловался на head []. Спасибо всем за вклад!

...