8

私は主にEitherモナドに興味があり、Control.Error. errors-1.0: Simplified error handling を読んで、純粋なエラーはIO エラーとは別にしておくべきだと確信しました。これはerrorfail、 、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

4

2 に答える 2

8

I now understand I was looking into a way to fold a list of composable actions. I came across this question, and learned about the Kleisli operator:

dereferenceValue :: ConfigParser -> String -> Either CPError String
dereferenceValue cp v = do
  foldr (>=>) return (fmap replacer ["executable", "args", "title"]) v
 where
  replacer :: String -> String -> Either CPError String
  replacer string res = do
    value <- get cp "DEFAULT" string
    return $ replace ("${" ++ string ++ "}") value res

Probably, this seems a bit like my question, but it feels cleaner. Particularly because of the signature of replacer. It doesn't receive a Monad as a second parameter and becomes more useful for other parts of code.

EDIT:

Even easier:

dereferenceValue :: ConfigParser -> String -> Either CPError String
dereferenceValue cp v = do
  foldM replacer v ["executable", "args", "title"]
 where
  replacer :: String -> String -> Either CPError String
  replacer res string = do
    value <- get cp "DEFAULT" string
    return $ replace ("${" ++ string ++ "}") value res

Conclusion: learn to use Hoogle

于 2014-06-01T22:52:26.670 に答える
4

あなたが発見したように、foldMここでは非常にうまく機能します。あなたのreplacer機能

replacer :: String -> String -> Either String String
replacer res string = do
  value <- get cp "DEFAULT" string
  return $ replace ("${" ++ string ++ "}") value res

次のように Applicative を使用してさらに美しくすることができます

replacer :: String -> String -> Either String String
replacer res string =
  replace ("${" ++ string ++ "}") <$> get cp "DEFAULT" string <*> pure res
于 2014-06-02T07:31:20.830 に答える