Everybody needs to validate something. From the content of a file to a web form.
data Address =
  Address {
    getHouseNumber :: Int,
    getStreetName :: String
  } deriving (Eq, Show)makeAddress :: Int -> String -> Maybe Addressdata Maybe a = Nothing | Just amakeAddress x y
  | x <= 0 || y == "" = Nothing
  | otherwise         = Just $ Address x ydata Person =
  Person {
    getName :: String,
    getAddress :: Address
  } deriving (Eq, Show)makePerson :: String -> Maybe Address -> Maybe PersonmakePerson n address
  | n == ""   = Nothing
  | otherwise = address >>= \a -> Just $ Person n adata Address =
  Address {
    getHouseNumber :: Int,
    getStreetName :: String
  } deriving (Eq, Show)makeAddress :: Int -> String -> Either Error Addressdata Either a b = Left a | Right bmakeAddress :: Int -> String -> Either Error AddressstreetNumberGreaterThanZero :: Int -> Either Error Int
streetNumberGreaterThanZero x
  | x <= 0    = Left "Number must be greater than zero!"
  | otherwise = Right xnotEmpty :: String -> Error -> Either Error String
notEmpty x err
  | x == ""   = Left err
  | otherwise = Right x
streetNameNotEmpty :: String -> Either Error String
streetNameNotEmpty x = notEmpty x "Street name must not be empty!"makeAddress x y = do
  number <- streetNumberGreaterThanZero x
  name   <- streetNameNotEmpty y
  Right $ Address number namedata Person =
  Person {
    getName :: String,
    getAddress :: Address
  } deriving (Eq, Show)makePerson :: String -> Either Error Address -> Either Error PersonnameNotEmpty :: String -> Either Error String
nameNotEmpty x = notEmpty x "Name must not be empty!"makePerson n a = do
  name    <- nameNotEmpty n
  address <- a
  Right $ Person name addressmakePerson' :: String -> Either Error Address -> Either Error Person
makePerson' n a =
  nameNotEmpty n >>= \name ->
  (Person name)  <$> adef makeAddress(number: Int, name: String): Address = {
  if (number <= 0) {
    throw new Exception("Street number must be greater than zero!")
  } else if (name.isEmpty) { 
    throw new Exception("Street name must not be empty!")
  } else if (name.length > 10) {
    throw new Exception("Street name must not have more than 10 characters!")
  } else {
    Address(number, name) 
  }
}def makePerson(name: String, address: Address): Person = {
  if (name.isEmpty) {
    throw new Exception("Name must not be empty!")
  } else if (address == null) {
    throw new IllegalArgumentException()
  } else {
    Person(name, address)
  }
}try {
  val address = makeAddress(0, "")
  val person  = makePerson("Gabi", address)
  println(person)
} catch {
  case e: Exception => println(e.getMessage)
}private def validateAddress(houseNumber: Int, streetName: String, notification: Notification) = {
  if (houseNumber <= 0)
    notification.addError("Street number must be greater than zero!")
  if (streetName.isEmpty)
    notification.addError("Street name must not be empty!")
  if (streetName.length > 10)
    notification.addError("Street name must not have more than 10 characters!")
}private def validatePerson(personName: String, notification: Notification) = {
  if (personName.isEmpty)
    notification.addError("Name must not be empty!")
}val notification = new Notification()
validateAddress(houseNumber, streetName, notification)
validatePerson(personName, notification)
val address = Address(houseNumber, streetName)
val person  = Person(personName, address)
if (notification.hasErrors) println(notification.reportErrors)
else println(person)data Address =
  Address {
    getHouseNumber :: Int,
    getStreetName :: String
  } deriving (Eq, Show)type Result a = Validation [Error] a
makeAddress :: Int -> String -> Result Addressdata Validation err a = Failure err | Success anumberGreaterThanZero :: Int -> Result Int
numberGreaterThanZero x
  | x > 0     = Success x
  | otherwise = Failure ["Number must be greater than zero!"]notEmpty :: String -> Error -> Result String
notEmpty x m
  | x == ""   = Failure [m]
  | otherwise = Success x
streetNameNotEmpty :: String -> Result String
streetNameNotEmpty x = notEmpty x "Street name must not be empty!"data Validation err a = Failure err | Success a
type Result a = Validation [Error] ainstance Functor (Validation a) where
  fmap _ (Failure e) = Failure e
  fmap f (Success x) = Success $ f xmakeAddress :: Int -> String -> Result Address
makeAddress x y = Address <$> numberGreaterThanZero x <*> streetNameNotEmpty yimport Data.Semigroup
instance Semigroup String where
  x <> y = x ++ yinstance Semigroup err => Applicative (Validation err) where
  pure = Success
  (Success f) <*> (Failure e) = Failure e
  (Failure e) <*> (Success x) = Failure e
  (Failure e) <*> (Failure t) = Failure $ e <> t
  (Success f) <*> (Success x) = Success $ f xdata Address =
  Address {
    getHouseNumber :: Int,
    getStreetName :: String
  } deriving (Eq, Show)streetNameLength :: String -> Result String
streetNameLength x
  | length x > 10 = Failure ["Name must not exceed 10 characters!"]
  | otherwise     = Success xinstance Semigroup err => Semigroup (Validation err a) where
  (Success x) <> (Success y) = Success y
  (Failure x) <> (Failure y) = Failure (x <> y)
  _           <> (Failure y) = Failure y
  (Failure x) <> _           = Failure xstreetNameValidation :: String -> Result String
streetNameValidation x = streetNameNotEmpty x <> streetNameLength xmakeAddress' :: Int -> String -> Result Address
makeAddress' x y = Address <$> numberGreaterThanZero x <*> streetNameValidation ydata Person =
  Person {
    getName :: String,
    getAddress :: Address
  } deriving (Eq, Show)makePerson :: String -> Result Address -> Result PersonnameNotEmpty :: String -> Result String
nameNotEmpty x = notEmpty x "Name must not be empty!"makePerson n a = Person <$> (nameNotEmpty n) <*> aSummarising
Summarising