Saya bertanya-tanya apa desain yang lebih baik untuk kegunaan / pemeliharaan, dan apa yang lebih baik sejauh sesuai dengan komunitas.
Diberikan model data:
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)
Saya dapat mengimplementasikan fungsi monadik untuk mengubah Pengguna misalnya dengan menambahkan item atau toko dll, tetapi saya mungkin berakhir dengan pengguna yang tidak valid sehingga fungsi monadik tersebut perlu memvalidasi pengguna yang mereka dapatkan dan atau buat.
Jadi, saya harus:
- membungkusnya dalam kesalahan monad dan membuat fungsi monadik menjalankan validasi
- membungkusnya dalam kesalahan monad dan membuat konsumen mengikat fungsi validasi monadik dalam urutan yang melemparkan respons kesalahan yang sesuai (sehingga mereka dapat memilih untuk tidak memvalidasi dan membawa-bawa objek pengguna yang tidak valid)
- sebenarnya membuatnya menjadi instance bind di User secara efektif membuat jenis kesalahan saya sendiri yang mengeksekusi validasi dengan setiap bind secara otomatis
Saya dapat melihat positif dan negatif dari masing-masing dari 3 pendekatan tetapi ingin tahu apa yang lebih umum dilakukan untuk skenario ini oleh masyarakat.
Jadi dalam istilah kode seperti ini, opsi 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"]
pilihan 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)
opsi 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"]