{-# OPTIONS_GHC -Wno-redundant-constraints #-}

-- | Exports unsafe functions.
--
-- @since 0.1.0.0
module Refined.Extras.Unsafe
  ( unsafeLiftR,
    unsafeLiftR2,
    unsafeLiftR3,
  )
where

import GHC.Stack (HasCallStack)
import Refined (Predicate, Refined)
import Refined qualified as R
import Refined.Extras.Utils (pattern MkRefined)
import Refined.Unsafe qualified as RUnsafe

-- $setup
-- >>> :set -XTemplateHaskell
-- >>> import Refined (Positive, SizeEqualTo, refineTH)

-- | Lifts a function onto 'Refined', dying with an error if the
-- predicate is not preserved. Intended for when we __know__ a function
-- preserves the refinement (e.g. addition of positive integers).
--
-- __WARNING: This function is not total. Exercise restraint!__
--
-- ==== __Examples__
-- >>> unsafeLiftR (fmap even) $$(refineTH @(SizeEqualTo 4) [2, 4, 1, 8])
-- Refined [True,True,False,True]
--
-- @since 0.1.0.0
unsafeLiftR ::
  (HasCallStack, Predicate p b) =>
  (a -> b) ->
  Refined p a ->
  Refined p b
unsafeLiftR :: forall {k} (p :: k) b a.
(HasCallStack, Predicate p b) =>
(a -> b) -> Refined p a -> Refined p b
unsafeLiftR a -> b
f = b -> Refined p b
forall {k} (p :: k) x. Predicate p x => x -> Refined p x
RUnsafe.unsafeRefine (b -> Refined p b)
-> (Refined p a -> b) -> Refined p a -> Refined p b
forall b c a. (b -> c) -> (a -> b) -> a -> c
. a -> b
f (a -> b) -> (Refined p a -> a) -> Refined p a -> b
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Refined p a -> a
forall {k} (p :: k) x. Refined p x -> x
R.unrefine

-- | Lifts a binary function onto 'Refined', dying with an error if the
-- predicate is not preserved. Intended for when we __know__ a function
-- preserves the refinement (e.g. addition of positive integers).
--
-- __WARNING: This function is not total. Exercise restraint!__
--
-- ==== __Examples__
-- >>> unsafeLiftR2 (+) $$(refineTH @Positive 7) $$(refineTH @Positive 11)
-- Refined 18
--
-- @since 0.1.0.0
unsafeLiftR2 ::
  (HasCallStack, Predicate p c) =>
  (a -> b -> c) ->
  Refined p a ->
  Refined p b ->
  Refined p c
unsafeLiftR2 :: forall {k} (p :: k) c a b.
(HasCallStack, Predicate p c) =>
(a -> b -> c) -> Refined p a -> Refined p b -> Refined p c
unsafeLiftR2 a -> b -> c
f (MkRefined a
x) = c -> Refined p c
forall {k} (p :: k) x. Predicate p x => x -> Refined p x
RUnsafe.unsafeRefine (c -> Refined p c)
-> (Refined p b -> c) -> Refined p b -> Refined p c
forall b c a. (b -> c) -> (a -> b) -> a -> c
. a -> b -> c
f a
x (b -> c) -> (Refined p b -> b) -> Refined p b -> c
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Refined p b -> b
forall {k} (p :: k) x. Refined p x -> x
R.unrefine

-- | Lifts a ternary function onto 'Refined', dying with an error if the
-- predicate is not preserved. Intended for when we __know__ a function
-- preserves the refinement (e.g. addition of positive integers).
--
-- __WARNING: This function is not total. Exercise restraint!__
--
-- ==== __Examples__
-- >>> unsafeLiftR3 (\x y z -> x + y + z) $$(refineTH @Positive 1) $$(refineTH @Positive 2) $$(refineTH @Positive 3)
-- Refined 6
--
-- @since 0.1.0.0
unsafeLiftR3 ::
  (HasCallStack, Predicate p d) =>
  (a -> b -> c -> d) ->
  Refined p a ->
  Refined p b ->
  Refined p c ->
  Refined p d
unsafeLiftR3 :: forall {k} (p :: k) d a b c.
(HasCallStack, Predicate p d) =>
(a -> b -> c -> d)
-> Refined p a -> Refined p b -> Refined p c -> Refined p d
unsafeLiftR3 a -> b -> c -> d
f (MkRefined a
x) (MkRefined b
y) =
  d -> Refined p d
forall {k} (p :: k) x. Predicate p x => x -> Refined p x
RUnsafe.unsafeRefine (d -> Refined p d)
-> (Refined p c -> d) -> Refined p c -> Refined p d
forall b c a. (b -> c) -> (a -> b) -> a -> c
. a -> b -> c -> d
f a
x b
y (c -> d) -> (Refined p c -> c) -> Refined p c -> d
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Refined p c -> c
forall {k} (p :: k) x. Refined p x -> x
R.unrefine