私は主にEither
モナドに興味があり、Control.Error
. errors-1.0: Simplified error handling を読んで、純粋なエラーはIO エラーとは別にしておくべきだと確信しました。これはerror
、fail
、 、exitFailure
が、その使用を IO モナドに減らすべき関数であることを意味します。純粋な計算では条件エラーが発生する可能性がありますが、決定論的です。
現在、foldsを扱っていると、配列内の要素が条件エラーを生成し、計算全体が満たされない状況が発生する可能性があります。例 ( Data.ConfigFileを使用):
type CPError = (CPErrorData, String)
data CPErrorData = ParseError String | ...
type SectionSpec = String
type OptionSpec = String
instance Error CPError
instance Error e => MonadError e (Either e)
get :: MonadError CPError m => ConfigParser -> SectionSpec -> OptionSpec -> m a
dereference :: ConfigParser -> String -> Either CPError String
dereference cp v = foldr replacer v ["executable", "args", "title"]
where
replacer :: String -> Either CPError String -> Either CPError String
replacer string acc = do
res <- acc
value <- get cp "DEFAULT" string
return $ replace ("${" ++ string ++ "}") value res
状況は次のとおりです。単一の要素が置換を実行していない場合、値全体を計算できないという理由だけで、複雑な型を持つ acc を使用しています。
私の質問は次のとおりです。これは醜いですか?これを行うより良い方法はありますか?いくつかの IO チェックEitherT CPError IO String
のために、タイプの厄介なユーティリティがいくつかあります。acc