I have a few nested records that I need to validate, and I wonder what is an idiomatic Haskell way to do it.
To simplify:
data Record = Record {
recordItemsA :: [ItemA],
recordItemB :: ItemB
} deriving (Show)
data ItemA {
itemAItemsC :: [ItemC]
} deriving (Show)
Requirements are:
- Collect and return all validation errors
- Some validations may be across items, e.g.
ItemsA
againstItemB
String
s are sufficient to represent errors
I currently have code that feels awkward:
type ErrorMsg = String
validate :: Record -> [ErrorMsg]
validate record =
recordValidations ++ itemAValidations ++ itemBValidations
where
recordValidations :: [ErrorMsg]
recordValidations = ensure (...) $
"Invalid combination: " ++ (show $ recordItemsA record) ++ " and " ++ (show $ recordItemsB record)
itemAValidations :: [ErrorMsg]
itemAValidations = concat $ map validateItemA $ recordItemsA record
validateItemA :: ItemA -> [ErrorMsg]
validateItemA itemA = ensure (...) $
"Invalid itemA: " ++ (show itemA)
itemBValidations :: [ErrorMsg]
itemBValidations = validateItemB $ recordItemB record
validateItemB :: ItemB -> [ErroMsg]
validateItemB itemB = ensure (...) $
"Invalid itemB: " ++ (show itemB)
ensure :: Bool -> ErrorMsg -> [ErrorMsg]
ensure b msg = if b then [] else [msg]