Ist dies ein gültiges Entwurfsmuster für eine Haskell-Hauptfunktion?

8

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 mainStruktur verlassen, um diese Trennung durchzusetzen.

Im Allgemeinen hat mein mainTestament 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?

recursion.ninja
quelle

Antworten:

7

Dieses Design macht mehrere nicht triviale Annahmen:

  • Die Eingabe des Benutzers hängt nicht von den Ergebnissen reiner oder unreiner Berechnungen ab.

  • Die unreinen Berechnungen hängen nicht vom Ergebnis reiner Berechnungen ab.

  • Die Programmlogik wird nicht wiederholt. es wird nur einmal ausgeführt.

Mein anderer Kommentar zu Ihrer Struktur ist, dass Sie die reinen und unreinen Berechnungen nicht trennen müssen. Das Typsystem von Haskell erledigt das bereits für Sie.

Trotzdem sieht diese Struktur für bestimmte Programmklassen sicherlich nützlich aus, insbesondere wenn Sie sicher sind, dass die oben beschriebenen Annahmen tatsächlich für Ihr Programm gelten. Es ist jedoch nicht etwas, das jedes Programm verwenden sollte.

WolfeFan
quelle
Wenn Sie Ihr Muster vereinfachen möchten, sollten Sie berücksichtigen, dass andOrGetUserInput mit ziemlicher Sicherheit als unreine orFalliableComputation gilt. Sie können sie wahrscheinlich in einem Abschnitt kombinieren.
WolfeFan
In der Praxis werden sie verdichtet; Zur Demonstration und Ausstellung habe ich sie getrennt.
recursion.ninja