Alex Rivera | Logout

Validations in Haskell

Asked 2012-01-04T03:16:16.617
11

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 against ItemB
  • Strings 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]
Edit
Report

1 Answer

0

One thing you might consider trying is, rather than validating your data afterwards, use lenses from the excellent fclabels package as your interface to your data (rather than pattern-matching/type constructors) to ensure that your data is always correct.

Check out the variant that supports failure here and build your lens by passing a setter and getter that do some validation on the datatype to the lens function.

If you need some more complicated error reporting or whatnot, take a look at the implementation of the Maybe variant of lens and define your lens in terms of the abstract interface.

answered 2012-01-04T22:16:25.863

Your Answer