{-# LANGUAGE Safe #-} {- | Module : Relude.Extra.Newtype Copyright : (c) 2018-2023 Kowainik SPDX-License-Identifier : MIT Maintainer : Kowainik <xrom.xkov@gmail.com> Stability : Stable Portability : Portable Functions to ease work with @newtypes@. @since 0.2.0 -} module Relude.Extra.Newtype ( un , wrap , under , under2 , underF2 , (#.) ) where import Relude -- $setup -- >>> :set -XTypeApplications -- >>> import Data.Semigroup (Max (..)) {- | Unwraps value from @newtype@. >>> newtype Size = Size Int deriving Show >>> un @Int (Size 5) 5 >>> un (Size 5) == length ['a', 'x', 'b'] False @since 0.2.0 -} un :: forall a n . Coercible a n => n -> a un :: forall a n. Coercible a n => n -> a un = n -> a forall a b. Coercible a b => a -> b coerce {-# INLINE un #-} {- | Wraps value to @newtype@. Behaves exactly as 'un' but has more meaningful name in case you need to convert some value to @newtype@. >>> newtype Flag = Flag Bool deriving (Show, Eq) >>> wrap False == Flag True False @since 0.2.0 -} wrap :: forall n a . Coercible a n => a -> n wrap :: forall n a. Coercible a n => a -> n wrap = a -> n forall a b. Coercible a b => a -> b coerce {-# INLINE wrap #-} {- | Applies function to the content of @newtype@. This function is not supposed to be used on @newtype@s that are created with the help of smart constructors. >>> newtype Foo = Foo Bool deriving Show >>> under not (Foo True) Foo False >>> newtype Bar = Bar String deriving Show >>> under (filter (== 'a')) (Bar "abacaba") Bar "aaaa" @since 0.2.0 -} under :: forall n a . Coercible a n => (n -> n) -> (a -> a) under :: forall n a. Coercible a n => (n -> n) -> a -> a under = (n -> n) -> a -> a forall a b. Coercible a b => a -> b coerce {-# INLINE under #-} {- | Lift binary function for @newtype@s to work over underlying @newtype@ representation. >>> under2 @(Sum Int) (<>) (3 :: Int) 4 7 >>> under2 @All (<>) True False False @since 0.3.0 -} under2 :: forall n a . Coercible a n => (n -> n -> n) -> (a -> a -> a) under2 :: forall n a. Coercible a n => (n -> n -> n) -> a -> a -> a under2 = (n -> n -> n) -> a -> a -> a forall a b. Coercible a b => a -> b coerce {-# INLINE under2 #-} {- | Version of 'under2' that works on @newtype@s parametrized by their representation. Provided for convenience. >>> underF2 @Sum (<>) (3 :: Int) 4 7 >>> underF2 @Max (<>) 'p' 't' 't' @since 0.3.0 -} underF2 :: forall n a . Coercible a (n a) => (n a -> n a -> n a) -> (a -> a -> a) underF2 :: forall (n :: * -> *) a. Coercible a (n a) => (n a -> n a -> n a) -> a -> a -> a underF2 = (n a -> n a -> n a) -> a -> a -> a forall a b. Coercible a b => a -> b coerce {-# INLINE underF2 #-} {- | Coercible composition. This function allows to write more efficient implementations of function compositions over @newtypes@. @since 0.3.0 -} (#.) :: Coercible b c => (b -> c) -> (a -> b) -> (a -> c) #. :: forall b c a. Coercible b c => (b -> c) -> (a -> b) -> a -> c (#.) b -> c _f = (a -> b) -> a -> c forall a b. Coercible a b => a -> b coerce {-# INLINE (#.) #-}