Каталог, пойманный Haskell, не существует, но не является пустым значением

С помощью 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

Что такое getDirContent? Я не могу найти его нигде. Я предполагаю, что это функция, которую вы написали сами; в таком случае, не могли бы вы включить его реализацию в свой пример кода? (Мне это нужно, чтобы получить минимальный воспроизводимый пример)

bradrn 29.05.2019 08:46
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
1
78
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

Вы можете заменить строку:

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), что проще, делая то же самое. Даже как человек, который действительно любит аппликативы, у меня возникли проблемы с разбором вашего утверждения.

bradrn 29.05.2019 12:30

решение typedfern не совсем то же самое (я знаю, что такое аппликативы, но не настолько опытен, чтобы знать, что и когда использовать). Он возвращает сообщение об ошибке, в то время как ваше решение (bradm) завершает вызов без сообщения. Оба ваших решения многому меня научили. Спасибо за это (даже без отсутствующего кода). Хотя код bradm более краток, typedfern предоставил информацию, которую я искал.

Madderote 29.05.2019 15:25
((not (null a) &&) <$> doesDirectoryExist a) >>= \case точно соответствует тому, что в этом ответе, но намного проще. Также обратите внимание, что у этого способа есть недостаток, заключающийся в том, что && не может закоротить бит ввода-вывода, тогда как способ unless bradrn не имеет этого недостатка.
Joseph Sible-Reinstate Monica 29.05.2019 17:12

Джозеф прав, выполняя (&&) <$> ioOp1 <*> ioOp2 выполняет ioOp2, даже когда он не нужен - в данном конкретном случае это не вредит, но лучше избегать; фиксированный.

typedfern 30.05.2019 00:00

Проблема в том, что doesDirectoryExist "" возвращает True, но то, что находится в вашей функции getDirContent (которую вам нужно опубликовать, если вы хотите получить более подробный ответ), не работает при передаче "".

Нет необходимости в Maybe или Either, чтобы исправить это. Просто оберните блок в конструкцию if и поместите что-то вроде putStrLn "You must enter a directory name" в else.

Джозеф Сибл: добавлен getDirContent. Я не заинтересован в том, если..тогда..иначе. Нравится case и больше охраняет, кажется немного яснее, поэтому я не выбрал эту конструкцию.

Madderote 29.05.2019 16:52

@Madderote, если вы понимаете, как это сделать с помощью if-then-else, переписать его для использования case и защиты тривиально.

Joseph Sible-Reinstate Monica 29.05.2019 17:08

ты прав. Простите мой комментарий. Просто мне больше нравится чистить внешний вид корпуса и гарды.

Madderote 29.05.2019 17:13

Другие вопросы по теме