Is it necessary to write Haskell generics in a recursive fashion?

Viewed 405

Most examples for Haskell generics do small bits of computation recursively around the :+: and :*: types/constructors. I seem to be solving a problem where this may not work out.

I'm trying to write a generic validation function that takes any two records having the same shape and validates each field in recordA against a validation function defined in recordB to return an error record of the same shape OR recordA itself.

Example:

-- Some type synonyms for better readability
type Name = Text
type Age = Int
type Email = Text
type GeneralError = Text
type FieldError = Text

-- a polymorphic record to help preserve the shape of various records
data User n a e = User {name :: n, age :: a, email :: e}

-- the incoming value which has been parsed into the correct type
-- but still needs various values to be validated, eg length, format, etc
type UserInput = User Name Age Email

-- specifies the exact errors for each field
type UserError = User [FieldError] [FieldError] [FieldError]

-- specifies how to validate each field. the validator is being passed
-- the complete record along with the specific field to allow
-- validations that depends on the value of another field
type UserValidator = User
                     (UserInput -> Name -> Either ([GeneralError], [FieldError]) Name)
                     (UserInput -> Age -> Either ([GeneralError], [FieldError]) Age)
                     (UserInput -> Email -> Either ([GeneralError], [FieldError]) Email)

let (validationResult :: Either ([GeneralError], UserError) UserInput)
  = genericValidation (i :: UserInput) (v :: UserValidator)

Now, the reason why doing this recursively around :*: might not work is, that one needs to look at the result of every validation function and then decide if the return value should be a Left ([GeneralError], UserError) or a Right UserInput. We cannot evaluate to a Left value on the first validation function that fails.

Is there any way to write this genericValidation function using Haskell generics?

2 Answers
Related