Ich frage mich, was das Design für Benutzerfreundlichkeit / Wartbarkeit besser macht und was besser zur Community passt.
Angesichts des Datenmodells:
type Name = String
data Amount = Out | Some | Enough | Plenty deriving (Show, Eq)
data Container = Container Name deriving (Show, Eq)
data Category = Category Name deriving (Show, Eq)
data Store = Store Name [Category] deriving (Show, Eq)
data Item = Item Name Container Category Amount Store deriving Show
instance Eq (Item) where
(==) i1 i2 = (getItemName i1) == (getItemName i2)
data User = User Name [Container] [Category] [Store] [Item] deriving Show
instance Eq (User) where
(==) u1 u2 = (getName u1) == (getName u2)
Ich kann monadische Funktionen implementieren, um den Benutzer zu transformieren, indem ich beispielsweise Elemente oder Speicher usw. hinzufüge, aber möglicherweise habe ich einen ungültigen Benutzer, sodass diese monadischen Funktionen den Benutzer validieren müssen, den sie erhalten und / oder erstellen.
Also, sollte ich nur:
- Wickeln Sie es in eine Fehlermonade und lassen Sie die monadischen Funktionen die Validierung ausführen
- Wickeln Sie es in eine Fehlermonade ein und lassen Sie den Verbraucher eine monadische Validierungsfunktion in der Reihenfolge binden, in der die entsprechende Fehlerantwort ausgelöst wird (damit er entscheiden kann, ein ungültiges Benutzerobjekt nicht zu validieren und herumzutragen).
- Bauen Sie es tatsächlich in eine Bindungsinstanz auf dem Benutzer ein und erstellen Sie effektiv meine eigene Art von Fehlermonade, die die Validierung bei jeder Bindung automatisch ausführt
Ich kann positive und negative Ergebnisse für jeden der drei Ansätze sehen, möchte aber wissen, was die Community für dieses Szenario häufiger tut.
Also in Code-Begriffen so etwas wie Option 1:
addStore s (User n1 c1 c2 s1 i1) = validate $ User n1 c1 c2 (s:s1) i1
updateUsersTable $ someUser >>= addStore $ Store "yay" ["category that doesnt exist, invalid argh"]
Option 2:
addStore s (User n1 c1 c2 s1 i1) = Right $ User n1 c1 c2 (s:s1) i1
updateUsersTable $ Right someUser >>= addStore $ Store "yay" ["category that doesnt exist, invalid argh"] >>= validate
-- in this choice, the validation could be pushed off to last possible moment (like inside updateUsersTable before db gets updated)
Option 3:
data ValidUser u = ValidUser u | InvalidUser u
instance Monad ValidUser where
(>>=) (ValidUser u) f = case return u of (ValidUser x) -> return f x; (InvalidUser y) -> return y
(>>=) (InvalidUser u) f = InvalidUser u
return u = validate u
addStore (Store s, User u, ValidUser vu) => s -> u -> vu
addStore s (User n1 c1 c2 s1 i1) = return $ User n1 c1 c2 (s:s1) i1
updateUsersTable $ someValidUser >>= addStore $ Store "yay" ["category that doesnt exist, invalid argh"]