Трудно сформулировать хорошие вопросы как новичок. Пожалуйста, задайте этот вопрос дружественным =)Могу ли я опустить монаду IO на эту чистую функцию?
Пытаясь написать мою первую «настоящую» программу Haskell (т. Е. Не только объекты Project Euler), я пытаюсь прочитать и проанализировать конфигурационный файл с хорошими сообщениями об ошибках. До сих пор у меня есть это:
import Prelude hiding (readFile)
import System.FilePath (FilePath)
import System.Directory (doesFileExist)
import Data.Aeson
import Control.Monad.Except
import Data.ByteString.Lazy (ByteString, readFile)
-- Type definitions without real educational value here
loadConfiguration :: FilePath -> ExceptT String IO Configuration
loadConfiguration path = do
fileContent <- readConfigurationFile "C:\\Temp\\config.json"
configuration <- parseConfiguration fileContent
return configuration
readConfigurationFile :: FilePath -> ExceptT String IO ByteString
readConfigurationFile path = do
fileExists <- liftIO $ doesFileExist path
if fileExists then do
fileContent <- liftIO $ readFile path
return fileContent
else
throwError $ "Configuration file not found at " ++ path ++ "."
parseConfiguration :: ByteString -> ExceptT String IO Configuration
parseConfiguration raw = do
let result = eitherDecode raw :: Either String Configuration
case result of
Left message -> throwError $ "Error parsing configuration file: " ++ message
Right configuration -> return configuration
Это работает, но монада IO в parseConfiguration
не является необходимым, и должен уйти. Но я не могу просто бросить его, конечно, и я еще не нашел способ изменить parseConfiguration
на что-то чистое, сохранив при этом близость loadConfiguration
.
Каков правильный способ написать это? Если на это ответили в документации, извините, но я ее не нашел. Я думаю, что чтение документации по хакерству - это умение, которое растет так же медленно, как и остальные мои навыки Хаскелла. =)
P.S .: Комментарии к другим ошибкам стиля, конечно, очень приветствуются!
Это выглядит как вы можете просто абстрагироваться от внутреннего типа монады? 'parseConfiguration :: Monad m => ByteString -> ExceptT String m Configuration' – Lee
В идеале вы должны иметь' parseConfiguration :: (Monad m, MonadError String m) => m Configuration'. – bheklilr
@bheklilr И если по какой-либо причине вы не используете 'mtl', можно использовать' mapExceptT (return. RunIdentity) :: Monad n => Except ea -> ExceptT ena' – danidiaz