-- SPDX-FileCopyrightText: 2021 Tocqueville Group
--
-- SPDX-License-Identifier: LicenseRef-MIT-TQ

{-# LANGUAGE NoImplicitPrelude #-}

-- | This module replaces the monomorphic boolean operators from 'Prelude'
-- with a set of polymorphic operators.
module Morley.Prelude.Boolean
  ( Boolean(..)
  , ApplicativeBoolean(..)
  ) where

import Universum hiding ((&&), (||))
import qualified Universum

-- | Generalized boolean operators.
class Boolean a where
  (&&) :: a -> a -> a
  (||) :: a -> a -> a
  infixr 3 &&
  infixr 2 ||

instance Boolean Bool where
  && :: Bool -> Bool -> Bool
(&&) = Bool -> Bool -> Bool
(Universum.&&)
  || :: Bool -> Bool -> Bool
(||) = Bool -> Bool -> Bool
(Universum.||)

-- | A newtype for deriving a 'Boolean' instance for any 'Applicative' type
-- constructor using @DerivingVia@.
newtype ApplicativeBoolean f bool = ApplicativeBoolean (f bool)
  deriving newtype (a -> ApplicativeBoolean f b -> ApplicativeBoolean f a
(a -> b) -> ApplicativeBoolean f a -> ApplicativeBoolean f b
(forall a b.
 (a -> b) -> ApplicativeBoolean f a -> ApplicativeBoolean f b)
-> (forall a b.
    a -> ApplicativeBoolean f b -> ApplicativeBoolean f a)
-> Functor (ApplicativeBoolean f)
forall a b. a -> ApplicativeBoolean f b -> ApplicativeBoolean f a
forall a b.
(a -> b) -> ApplicativeBoolean f a -> ApplicativeBoolean f b
forall (f :: * -> *) a b.
Functor f =>
a -> ApplicativeBoolean f b -> ApplicativeBoolean f a
forall (f :: * -> *) a b.
Functor f =>
(a -> b) -> ApplicativeBoolean f a -> ApplicativeBoolean f b
forall (f :: * -> *).
(forall a b. (a -> b) -> f a -> f b)
-> (forall a b. a -> f b -> f a) -> Functor f
<$ :: a -> ApplicativeBoolean f b -> ApplicativeBoolean f a
$c<$ :: forall (f :: * -> *) a b.
Functor f =>
a -> ApplicativeBoolean f b -> ApplicativeBoolean f a
fmap :: (a -> b) -> ApplicativeBoolean f a -> ApplicativeBoolean f b
$cfmap :: forall (f :: * -> *) a b.
Functor f =>
(a -> b) -> ApplicativeBoolean f a -> ApplicativeBoolean f b
Functor, Functor (ApplicativeBoolean f)
a -> ApplicativeBoolean f a
Functor (ApplicativeBoolean f)
-> (forall a. a -> ApplicativeBoolean f a)
-> (forall a b.
    ApplicativeBoolean f (a -> b)
    -> ApplicativeBoolean f a -> ApplicativeBoolean f b)
-> (forall a b c.
    (a -> b -> c)
    -> ApplicativeBoolean f a
    -> ApplicativeBoolean f b
    -> ApplicativeBoolean f c)
-> (forall a b.
    ApplicativeBoolean f a
    -> ApplicativeBoolean f b -> ApplicativeBoolean f b)
-> (forall a b.
    ApplicativeBoolean f a
    -> ApplicativeBoolean f b -> ApplicativeBoolean f a)
-> Applicative (ApplicativeBoolean f)
ApplicativeBoolean f a
-> ApplicativeBoolean f b -> ApplicativeBoolean f b
ApplicativeBoolean f a
-> ApplicativeBoolean f b -> ApplicativeBoolean f a
ApplicativeBoolean f (a -> b)
-> ApplicativeBoolean f a -> ApplicativeBoolean f b
(a -> b -> c)
-> ApplicativeBoolean f a
-> ApplicativeBoolean f b
-> ApplicativeBoolean f c
forall a. a -> ApplicativeBoolean f a
forall a b.
ApplicativeBoolean f a
-> ApplicativeBoolean f b -> ApplicativeBoolean f a
forall a b.
ApplicativeBoolean f a
-> ApplicativeBoolean f b -> ApplicativeBoolean f b
forall a b.
ApplicativeBoolean f (a -> b)
-> ApplicativeBoolean f a -> ApplicativeBoolean f b
forall a b c.
(a -> b -> c)
-> ApplicativeBoolean f a
-> ApplicativeBoolean f b
-> ApplicativeBoolean f c
forall (f :: * -> *).
Functor f
-> (forall a. a -> f a)
-> (forall a b. f (a -> b) -> f a -> f b)
-> (forall a b c. (a -> b -> c) -> f a -> f b -> f c)
-> (forall a b. f a -> f b -> f b)
-> (forall a b. f a -> f b -> f a)
-> Applicative f
forall (f :: * -> *).
Applicative f =>
Functor (ApplicativeBoolean f)
forall (f :: * -> *) a.
Applicative f =>
a -> ApplicativeBoolean f a
forall (f :: * -> *) a b.
Applicative f =>
ApplicativeBoolean f a
-> ApplicativeBoolean f b -> ApplicativeBoolean f a
forall (f :: * -> *) a b.
Applicative f =>
ApplicativeBoolean f a
-> ApplicativeBoolean f b -> ApplicativeBoolean f b
forall (f :: * -> *) a b.
Applicative f =>
ApplicativeBoolean f (a -> b)
-> ApplicativeBoolean f a -> ApplicativeBoolean f b
forall (f :: * -> *) a b c.
Applicative f =>
(a -> b -> c)
-> ApplicativeBoolean f a
-> ApplicativeBoolean f b
-> ApplicativeBoolean f c
<* :: ApplicativeBoolean f a
-> ApplicativeBoolean f b -> ApplicativeBoolean f a
$c<* :: forall (f :: * -> *) a b.
Applicative f =>
ApplicativeBoolean f a
-> ApplicativeBoolean f b -> ApplicativeBoolean f a
*> :: ApplicativeBoolean f a
-> ApplicativeBoolean f b -> ApplicativeBoolean f b
$c*> :: forall (f :: * -> *) a b.
Applicative f =>
ApplicativeBoolean f a
-> ApplicativeBoolean f b -> ApplicativeBoolean f b
liftA2 :: (a -> b -> c)
-> ApplicativeBoolean f a
-> ApplicativeBoolean f b
-> ApplicativeBoolean f c
$cliftA2 :: forall (f :: * -> *) a b c.
Applicative f =>
(a -> b -> c)
-> ApplicativeBoolean f a
-> ApplicativeBoolean f b
-> ApplicativeBoolean f c
<*> :: ApplicativeBoolean f (a -> b)
-> ApplicativeBoolean f a -> ApplicativeBoolean f b
$c<*> :: forall (f :: * -> *) a b.
Applicative f =>
ApplicativeBoolean f (a -> b)
-> ApplicativeBoolean f a -> ApplicativeBoolean f b
pure :: a -> ApplicativeBoolean f a
$cpure :: forall (f :: * -> *) a.
Applicative f =>
a -> ApplicativeBoolean f a
$cp1Applicative :: forall (f :: * -> *).
Applicative f =>
Functor (ApplicativeBoolean f)
Applicative)

instance (Applicative f, Boolean bool) => Boolean (ApplicativeBoolean f bool) where
  && :: ApplicativeBoolean f bool
-> ApplicativeBoolean f bool -> ApplicativeBoolean f bool
(&&) = (bool -> bool -> bool)
-> ApplicativeBoolean f bool
-> ApplicativeBoolean f bool
-> ApplicativeBoolean f bool
forall (f :: * -> *) a b c.
Applicative f =>
(a -> b -> c) -> f a -> f b -> f c
liftA2 bool -> bool -> bool
forall a. Boolean a => a -> a -> a
(&&)
  || :: ApplicativeBoolean f bool
-> ApplicativeBoolean f bool -> ApplicativeBoolean f bool
(||) = (bool -> bool -> bool)
-> ApplicativeBoolean f bool
-> ApplicativeBoolean f bool
-> ApplicativeBoolean f bool
forall (f :: * -> *) a b c.
Applicative f =>
(a -> b -> c) -> f a -> f b -> f c
liftA2 bool -> bool -> bool
forall a. Boolean a => a -> a -> a
(||)

deriving via (ApplicativeBoolean IO bool) instance Boolean bool => Boolean (IO bool)
deriving via (ApplicativeBoolean ((->) a) bool) instance Boolean bool => Boolean (a -> bool)