{-# LANGUAGE DeriveAnyClass #-}
{-# LANGUAGE OverloadedStrings #-}
module Data.Ext where
import Control.Lens hiding ((.=))
import Data.Biapplicative
import Data.Bifoldable
import Data.Bifunctor.Apply
import Data.Bitraversable
import Data.Functor.Apply (liftF2)
import Data.Semigroup
import Data.Semigroup.Bifoldable
import Data.Semigroup.Bitraversable
import GHC.Generics (Generic)
import Control.DeepSeq
import Data.Aeson
import Data.Aeson.Types(typeMismatch)
data core :+ extra = core :+ extra deriving (Show,Read,Eq,Ord,Bounded,Generic,NFData)
infixr 1 :+
instance Bifunctor (:+) where
bimap f g (c :+ e) = f c :+ g e
instance Biapply (:+) where
(f :+ g) <<.>> (c :+ e) = f c :+ g e
instance Biapplicative (:+) where
bipure = (:+)
(f :+ g) <<*>> (c :+ e) = f c :+ g e
instance Bifoldable (:+) where
bifoldMap f g (c :+ e) = f c `mappend` g e
instance Bitraversable (:+) where
bitraverse f g (c :+ e) = (:+) <$> f c <*> g e
instance Bifoldable1 (:+)
instance Bitraversable1 (:+) where
bitraverse1 f g (c :+ e) = liftF2 (:+) (f c) (g e)
instance (Semigroup core, Semigroup extra) => Semigroup (core :+ extra) where
(c :+ e) <> (c' :+ e') = c <> c' :+ e <> e'
instance (ToJSON core, ToJSON extra) => ToJSON (core :+ extra) where
toJSON (c :+ e) = object ["core" .= c, "extra" .= e]
toEncoding (c :+ e) = pairs ("core" .= c <> "extra" .= e)
instance (FromJSON core, FromJSON extra) => FromJSON (core :+ extra) where
parseJSON (Object v) = (:+) <$> v .: "core" <*> v .: "extra"
parseJSON invalid = typeMismatch "Ext (:+)" invalid
_core :: (core :+ extra) -> core
_core (c :+ _) = c
_extra :: (core :+ extra) -> extra
_extra (_ :+ e) = e
core :: Lens (core :+ extra) (core' :+ extra) core core'
core = lens _core (\(_ :+ e) c -> (c :+ e))
extra :: Lens (core :+ extra) (core :+ extra') extra extra'
extra = lens _extra (\(c :+ _) e -> (c :+ e))
ext :: a -> a :+ ()
ext x = x :+ ()