{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE UndecidableInstances #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE FunctionalDependencies #-}
{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE ViewPatterns #-}
import GHC.Generics

-- from https://ocharles.org.uk/blog/posts/2014-12-16-derive-generic.html

data Valid e a = Error e | OK a
  deriving (Generic)

toEither :: Valid e a -> Either e a
toEither (Error e) = Left e
toEither (OK a) = Right a

fromEither :: Either e a -> Valid e a
fromEither (Left e) = Error e
fromEither (Right a) = OK a

-- ---------------------------------------------------------------------

class GetError rep e | rep -> e where
  getError' :: rep a -> Maybe e

instance GetError f e => GetError (M1 i c f) e where
  getError' (M1 m1) = getError' m1

instance GetError l e => GetError (l :+: r) e where
  getError' (L1 l) = getError' l
  getError' (R1 _) = Nothing

instance GetError (K1 i e) e where
  getError' (K1 e) = Just e

getError :: (Generic (errorLike e a), GetError (Rep (errorLike e a)) e) => errorLike e a -> Maybe e
getError = getError' . from