Nachdem ich mehrere Haskell-Anwendungen entwickelt hatte, habe ich festgestellt, dass ich unreinen Code und fehlerhafte ( Teil- ) Funktionen rigoros von ihren reinen und vollständigen Gegenstücken getrennt habe. Diese Bemühungen haben die mit den Anwendungen verbundenen Wartungskosten spürbar reduziert. Ich habe mich im Laufe der Zeit auf dieselbe hochrangige main
Struktur verlassen, um diese Trennung durchzusetzen.
Im Allgemeinen hat mein main
Testament die folgende Struktur:
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
Das Ziel besteht darin, Teilberechnungen in einer Monade zusammenzuführen und eine vollständige monadische Berechnung zu erstellen.
Dies ist zu einem Muster in der Codebasis geworden, und ich möchte eine Rückmeldung darüber, ob es sich um ein Entwurfsmuster oder ein Anti-Muster handelt .
Ist dies eine idiomatische Methode, um Teilberechnungen zu trennen und abzufangen?
Gibt es bemerkenswerte Nachteile dieser hohen Segregation?
Gibt es bessere Abstraktionstechniken?