С помощью LambdaCase
я могу отфильтровать, если каталог не существует. Однако: если пользователю предлагается и он нажимает ввод (пусто), я все равно получаю исключение.
Я думаю, что Maybe
или Either
могут помочь мне здесь, но мне трудно понять, как это настроить.
{-# LANGUAGE LambdaCase #-}
import System.Directory
import System.IO
dirExist = do
a <- prompt "Directory:> "
doesDirectoryExist a >>= \case
True -> getDirContent a
_ -> putStrLn "Directory does not exist or invalid value specified."
getDirContent :: FilePath -> IO ()
getDirContent dir = do
result <- getDirectoryContents dir
mapM_ putStrLn $ result
prompt :: String -> IO String
prompt x = do
putStr x
a <- getLine
return a
Вы можете заменить строку:
doesDirectoryExist a >>= \case
с участием:
((&&) <$> (pure $ not $ null a) <*> doesDirectoryExist a) >>= \case
Это называется "аппликативным стилем" (если вы этого не знали ;-)); Я объединяю две операции ввода-вывода, которые возвращают логическое значение с помощью оператора AND (&&).
Выражение (pure $ not $ null a) проверяет, что строка не пуста, и использует «pure» для поднятия чистой операции в IO (поэтому мы можем объединить ее с doDirectoryExist в выражение, которое проверяет оба условия).
Обновлено:
Как заметил Джозеф, вышеприведенное выполняет doDirectoryExist независимо от того, нужно это или нет; обычно вы хотите этого избежать (если только вы не полагаетесь на его побочные эффекты); вы можете избежать этого с предложением bradrn; вы также можете сделать это:
(if null a then pure False else doesDirectoryExist a) >>= \case
В качестве альтернативы, поскольку вам не нравится обозначение if-then-else (как и мне):
(case null a of True -> pure False; False -> doesDirectoryExist a) >>= \case
Однако не совсем чище; вы можете импортировать Data.Bool и сделать это:
-- import Data.Bool
(bool (doesDirectoryExist a) (pure False) $ null a) >>= \case
("bool" - это просто более функциональная запись для старого доброго if-then-else)
Я думаю, стоит отметить, что это эквивалентно unless (null a) $ doesDirectoryExist a >>= \case
(используя unless
из Control.Monad
), что проще, делая то же самое. Даже как человек, который действительно любит аппликативы, у меня возникли проблемы с разбором вашего утверждения.
решение typedfern не совсем то же самое (я знаю, что такое аппликативы, но не настолько опытен, чтобы знать, что и когда использовать). Он возвращает сообщение об ошибке, в то время как ваше решение (bradm) завершает вызов без сообщения. Оба ваших решения многому меня научили. Спасибо за это (даже без отсутствующего кода). Хотя код bradm более краток, typedfern предоставил информацию, которую я искал.
((not (null a) &&) <$> doesDirectoryExist a) >>= \case
точно соответствует тому, что в этом ответе, но намного проще. Также обратите внимание, что у этого способа есть недостаток, заключающийся в том, что &&
не может закоротить бит ввода-вывода, тогда как способ unless
bradrn не имеет этого недостатка.
Джозеф прав, выполняя (&&) <$> ioOp1 <*> ioOp2 выполняет ioOp2, даже когда он не нужен - в данном конкретном случае это не вредит, но лучше избегать; фиксированный.
Проблема в том, что doesDirectoryExist ""
возвращает True
, но то, что находится в вашей функции getDirContent
(которую вам нужно опубликовать, если вы хотите получить более подробный ответ), не работает при передаче ""
.
Нет необходимости в Maybe
или Either
, чтобы исправить это. Просто оберните блок в конструкцию if
и поместите что-то вроде putStrLn "You must enter a directory name"
в else
.
Джозеф Сибл: добавлен getDirContent. Я не заинтересован в том, если..тогда..иначе. Нравится case
и больше охраняет, кажется немного яснее, поэтому я не выбрал эту конструкцию.
@Madderote, если вы понимаете, как это сделать с помощью if-then-else, переписать его для использования case
и защиты тривиально.
ты прав. Простите мой комментарий. Просто мне больше нравится чистить внешний вид корпуса и гарды.
Что такое
getDirContent
? Я не могу найти его нигде. Я предполагаю, что это функция, которую вы написали сами; в таком случае, не могли бы вы включить его реализацию в свой пример кода? (Мне это нужно, чтобы получить минимальный воспроизводимый пример)