いくつかのHaskellアプリケーションを開発した後、純粋でないコードと完全なコードから、不純なコードと失敗する可能性のある(部分)関数を厳密に分離していることに気付きました。これらの取り組みにより、アプリケーションに関連するメンテナンスコストが大幅に削減されました。私は、時間の経過とともに、この分離を実施するために同じ高レベルの構造に依存していることに気づきました。main
一般的に、私main
は次のような構造になります。
import System.Environment
data ProgramParameters = P ()
data ComputationResult = I ()
main :: IO ()
main = getArgs -- Collect arguments
>>= andOrGetUserInput -- Collect user input
>>= impureOrFailableComputations -- Possible non-recoverable error(s)
>>= either -- "Branch"
putStrLn -- Print Any Failure(s)
pureNotFailableComputations -- Finish the work
andOrGetUserInput :: [String] -> IO ProgramParameters
andOrGetUserInput = undefined
impureOrFailableComputations :: ProgramParameters -> IO (Either String ComputationResult)
impureOrFailableComputations = undefined -- a composition of partial functions
-- made total by catching exceptions & input errors
-- in the short-circuiting ErrorT/EitherT monad
pureNotFailableComputations :: ComputationResult -> IO ()
pureNotFailableComputations = undefined -- a composition of total functions
目標は、モナド内の部分的な計算を合体させ、完全なモナド計算を作成することです。
これはコードベースのパターンになっています。これがデザインパターンであるかアンチパターンであるかについてフィードバックをお願いします。
これは部分的な計算を分離してキャッチする慣用的な方法ですか?
この高レベルの分離には注目すべき欠点はありますか?
より良い抽象化手法はありますか?