{-# LANGUAGE TypeOperators #-}

module Data.Vinyl.Validation where

import           Control.Applicative
import           Control.Monad.Identity
import           Data.Monoid
import           Data.Vinyl.Classes

-- | A type which is similar to 'Either', except that it has a
-- slightly different Applicative instance.
data Result e a
  = Failure e
  | Success a
  deriving (Show, Eq)

-- | Validators transform identities into results.
type Validator e = Identity ~> Result e

instance Functor (Result e) where
  fmap f (Success x) = Success $ f x
  fmap f (Failure e) = Failure e

-- | The 'Applicative' instance to 'Result' relies on its error type
-- being a 'Monoid'. That way, it can accumulate errors.
instance Monoid e => Applicative (Result e) where
  pure = Success
  (Success f) <*> (Success x)  = Success $ f x
  (Failure e) <*> (Success x)  = Failure e
  (Success f) <*> (Failure e)  = Failure e
  (Failure e) <*> (Failure e') = Failure $ e <> e'