1{-# LANGUAGE CPP #-} 2{-# LANGUAGE TypeFamilies #-} 3{-# LANGUAGE FlexibleContexts, FlexibleInstances #-} 4{-# LANGUAGE DefaultSignatures #-} 5{-# LANGUAGE DeriveDataTypeable #-} 6{-# LANGUAGE StandaloneDeriving #-} 7{-# LANGUAGE GeneralizedNewtypeDeriving #-} 8-- | "Data.NonNull" extends the concepts from 9-- "Data.List.NonEmpty" to any 'MonoFoldable'. 10-- 11-- 'NonNull' is a newtype wrapper for a container with 1 or more elements. 12module Data.NonNull ( 13 NonNull 14 , fromNullable 15 , impureNonNull 16 , nonNull 17 , toNullable 18 , fromNonEmpty 19 , toNonEmpty 20 , ncons 21 , nuncons 22 , splitFirst 23 , nfilter 24 , nfilterM 25 , nReplicate 26 , head 27 , tail 28 , last 29 , init 30 , ofoldMap1 31 , ofold1 32 , ofoldr1 33 , ofoldl1' 34 , maximum 35 , maximumBy 36 , minimum 37 , minimumBy 38 , (<|) 39 , toMinList 40 , mapNonNull 41 , GrowingAppend 42) where 43 44import Prelude hiding (head, tail, init, last, reverse, seq, filter, replicate, maximum, minimum) 45import Control.Arrow (second) 46import Control.Exception.Base (Exception, throw) 47#if !MIN_VERSION_base(4,8,0) 48import Control.Monad (liftM) 49#endif 50import Data.Data 51import qualified Data.List.NonEmpty as NE 52import Data.Maybe (fromMaybe) 53import Data.MonoTraversable 54import Data.Sequences 55import Data.Semigroup (Semigroup (..)) 56import Control.Monad.Trans.State.Strict (evalState, state) 57 58data NullError = NullError String deriving (Show, Typeable) 59instance Exception NullError 60 61-- | A monomorphic container that is not null. 62newtype NonNull mono = NonNull 63 { toNullable :: mono 64 -- ^ __Safely__ convert from a non-null monomorphic container to a nullable monomorphic container. 65 } 66 deriving (Eq, Ord, Read, Show, Data, Typeable) 67type instance Element (NonNull mono) = Element mono 68deriving instance MonoFunctor mono => MonoFunctor (NonNull mono) 69deriving instance MonoFoldable mono => MonoFoldable (NonNull mono) 70instance MonoTraversable mono => MonoTraversable (NonNull mono) where 71 otraverse f (NonNull x) = fmap NonNull (otraverse f x) 72 {-# INLINE otraverse #-} 73#if !MIN_VERSION_base(4,8,0) 74 omapM f (NonNull x) = liftM NonNull (omapM f x) 75 {-# INLINE omapM #-} 76#endif 77instance GrowingAppend mono => GrowingAppend (NonNull mono) 78 79instance (Semigroup mono, GrowingAppend mono) => Semigroup (NonNull mono) where 80 NonNull x <> NonNull y = NonNull (x <> y) 81 82instance SemiSequence seq => SemiSequence (NonNull seq) where 83 type Index (NonNull seq) = Index seq 84 85 intersperse e = unsafeMap $ intersperse e 86 reverse = unsafeMap reverse 87 find f = find f . toNullable 88 cons x = unsafeMap $ cons x 89 snoc xs x = unsafeMap (flip snoc x) xs 90 sortBy f = unsafeMap $ sortBy f 91 92-- | This function is unsafe, and must not be exposed from this module. 93unsafeMap :: (mono -> mono) -> NonNull mono -> NonNull mono 94unsafeMap f (NonNull x) = NonNull (f x) 95 96instance MonoPointed mono => MonoPointed (NonNull mono) where 97 opoint = NonNull . opoint 98 {-# INLINE opoint #-} 99instance IsSequence mono => MonoComonad (NonNull mono) where 100 oextract = head 101 oextend f (NonNull mono) = NonNull 102 . flip evalState mono 103 . ofor mono 104 . const 105 . state 106 $ \mono' -> (f (NonNull mono'), tailEx mono') 107 108-- | __Safely__ convert from an __unsafe__ monomorphic container to a __safe__ 109-- non-null monomorphic container. 110fromNullable :: MonoFoldable mono => mono -> Maybe (NonNull mono) 111fromNullable mono 112 | onull mono = Nothing 113 | otherwise = Just (NonNull mono) 114 115-- | __Unsafely__ convert from an __unsafe__ monomorphic container to a __safe__ 116-- non-null monomorphic container. 117-- 118-- Throws an exception if the monomorphic container is empty. 119-- 120-- @since 1.0.0 121impureNonNull :: MonoFoldable mono => mono -> NonNull mono 122impureNonNull nullable = 123 fromMaybe (throw $ NullError "Data.NonNull.impureNonNull (NonNull default): expected non-null") 124 $ fromNullable nullable 125 126-- | Old synonym for 'impureNonNull' 127nonNull :: MonoFoldable mono => mono -> NonNull mono 128nonNull = impureNonNull 129{-# DEPRECATED nonNull "Please use the more explicit impureNonNull instead" #-} 130 131-- | __Safely__ convert from a 'NonEmpty' list to a non-null monomorphic container. 132fromNonEmpty :: IsSequence seq => NE.NonEmpty (Element seq) -> NonNull seq 133fromNonEmpty = impureNonNull . fromList . NE.toList 134{-# INLINE fromNonEmpty #-} 135 136-- | __Safely__ convert from a 'NonNull' container to a 'NonEmpty' list. 137-- 138-- @since 1.0.15.0 139toNonEmpty :: MonoFoldable mono => NonNull mono -> NE.NonEmpty (Element mono) 140toNonEmpty = NE.fromList . otoList 141 142-- | Specializes 'fromNonEmpty' to lists only. 143toMinList :: NE.NonEmpty a -> NonNull [a] 144toMinList = fromNonEmpty 145 146-- | Prepend an element to a 'SemiSequence', creating a non-null 'SemiSequence'. 147-- 148-- Generally this uses cons underneath. 149-- cons is not efficient for most data structures. 150-- 151-- Alternatives: 152-- 153-- * if you don't need to cons, use 'fromNullable' or 'nonNull' if you can create your structure in one go. 154-- * if you need to cons, you might be able to start off with an efficient data structure such as a 'NonEmpty' List. 155-- 'fronNonEmpty' will convert that to your data structure using the structure's fromList function. 156ncons :: SemiSequence seq => Element seq -> seq -> NonNull seq 157ncons x xs = nonNull $ cons x xs 158 159-- | Extract the first element of a sequnce and the rest of the non-null sequence if it exists. 160nuncons :: IsSequence seq => NonNull seq -> (Element seq, Maybe (NonNull seq)) 161nuncons xs = 162 second fromNullable 163 $ fromMaybe (error "Data.NonNull.nuncons: data structure is null, it should be non-null") 164 $ uncons (toNullable xs) 165 166-- | Same as 'nuncons' with no guarantee that the rest of the sequence is non-null. 167splitFirst :: IsSequence seq => NonNull seq -> (Element seq, seq) 168splitFirst xs = 169 fromMaybe (error "Data.NonNull.splitFirst: data structure is null, it should be non-null") 170 $ uncons (toNullable xs) 171 172-- | Equivalent to @"Data.Sequences".'Data.Sequences.filter'@, 173-- but works on non-nullable sequences. 174nfilter :: IsSequence seq => (Element seq -> Bool) -> NonNull seq -> seq 175nfilter f = filter f . toNullable 176 177-- | Equivalent to @"Data.Sequences".'Data.Sequences.filterM'@, 178-- but works on non-nullable sequences. 179nfilterM :: (Monad m, IsSequence seq) => (Element seq -> m Bool) -> NonNull seq -> m seq 180nfilterM f = filterM f . toNullable 181 182-- | Equivalent to @"Data.Sequences".'Data.Sequences.replicate'@ 183-- 184-- @i@ must be @> 0@ 185-- 186-- @i <= 0@ is treated the same as providing @1@ 187nReplicate :: IsSequence seq => Index seq -> Element seq -> NonNull seq 188nReplicate i = nonNull . replicate (max 1 i) 189 190-- | __Safe__ version of 'tailEx', only working on non-nullable sequences. 191tail :: IsSequence seq => NonNull seq -> seq 192tail = tailEx . toNullable 193{-# INLINE tail #-} 194 195-- | __Safe__ version of 'initEx', only working on non-nullable sequences. 196init :: IsSequence seq => NonNull seq -> seq 197init = initEx . toNullable 198{-# INLINE init #-} 199 200infixr 5 <| 201 202-- | Prepend an element to a non-null 'SemiSequence'. 203(<|) :: SemiSequence seq => Element seq -> NonNull seq -> NonNull seq 204x <| y = ncons x (toNullable y) 205 206-- | Return the first element of a monomorphic container. 207-- 208-- Safe version of 'headEx', only works on monomorphic containers wrapped in a 209-- 'NonNull'. 210head :: MonoFoldable mono => NonNull mono -> Element mono 211head = headEx . toNullable 212{-# INLINE head #-} 213 214-- | Return the last element of a monomorphic container. 215-- 216-- Safe version of 'lastEx', only works on monomorphic containers wrapped in a 217-- 'NonNull'. 218last :: MonoFoldable mono => NonNull mono -> Element mono 219last = lastEx . toNullable 220{-# INLINE last #-} 221 222-- | Map each element of a monomorphic container to a semigroup, and combine the 223-- results. 224-- 225-- Safe version of 'ofoldMap1Ex', only works on monomorphic containers wrapped in a 226-- 'NonNull'. 227-- 228-- ==== __Examples__ 229-- 230-- @ 231-- > let xs = ncons ("hello", 1 :: 'Integer') [(" world", 2)] 232-- > 'ofoldMap1' 'fst' xs 233-- "hello world" 234-- @ 235ofoldMap1 :: (MonoFoldable mono, Semigroup m) => (Element mono -> m) -> NonNull mono -> m 236ofoldMap1 f = ofoldMap1Ex f . toNullable 237{-# INLINE ofoldMap1 #-} 238 239-- | Join a monomorphic container, whose elements are 'Semigroup's, together. 240-- 241-- Safe, only works on monomorphic containers wrapped in a 'NonNull'. 242-- 243-- ==== __Examples__ 244-- 245-- @ 246-- > let xs = ncons "a" ["b", "c"] 247-- > xs 248-- 'NonNull' {toNullable = ["a","b","c"]} 249-- 250-- > 'ofold1' xs 251-- "abc" 252-- @ 253ofold1 :: (MonoFoldable mono, Semigroup (Element mono)) => NonNull mono -> Element mono 254ofold1 = ofoldMap1 id 255{-# INLINE ofold1 #-} 256 257-- | Right-associative fold of a monomorphic container with no base element. 258-- 259-- Safe version of 'ofoldr1Ex', only works on monomorphic containers wrapped in a 260-- 'NonNull'. 261-- 262-- @'foldr1' f = "Prelude".'Prelude.foldr1' f . 'otoList'@ 263-- 264-- ==== __Examples__ 265-- 266-- @ 267-- > let xs = ncons "a" ["b", "c"] 268-- > 'ofoldr1' (++) xs 269-- "abc" 270-- @ 271ofoldr1 :: MonoFoldable mono 272 => (Element mono -> Element mono -> Element mono) 273 -> NonNull mono 274 -> Element mono 275ofoldr1 f = ofoldr1Ex f . toNullable 276{-# INLINE ofoldr1 #-} 277 278-- | Strict left-associative fold of a monomorphic container with no base 279-- element. 280-- 281-- Safe version of 'ofoldl1Ex'', only works on monomorphic containers wrapped in a 282-- 'NonNull'. 283-- 284-- @'foldl1'' f = "Prelude".'Prelude.foldl1'' f . 'otoList'@ 285-- 286-- ==== __Examples__ 287-- 288-- @ 289-- > let xs = ncons "a" ["b", "c"] 290-- > 'ofoldl1'' (++) xs 291-- "abc" 292-- @ 293ofoldl1' :: MonoFoldable mono 294 => (Element mono -> Element mono -> Element mono) 295 -> NonNull mono 296 -> Element mono 297ofoldl1' f = ofoldl1Ex' f . toNullable 298{-# INLINE ofoldl1' #-} 299 300-- | Get the maximum element of a monomorphic container. 301-- 302-- Safe version of 'maximumEx', only works on monomorphic containers wrapped in a 303-- 'NonNull'. 304-- 305-- ==== __Examples__ 306-- 307-- @ 308-- > let xs = ncons 1 [2, 3 :: Int] 309-- > 'maximum' xs 310-- 3 311-- @ 312maximum :: (MonoFoldable mono, Ord (Element mono)) 313 => NonNull mono 314 -> Element mono 315maximum = maximumEx . toNullable 316{-# INLINE maximum #-} 317 318-- | Get the minimum element of a monomorphic container. 319-- 320-- Safe version of 'minimumEx', only works on monomorphic containers wrapped in a 321-- 'NonNull'. 322-- 323-- ==== __Examples__ 324-- 325-- @ 326-- > let xs = ncons 1 [2, 3 :: Int] 327-- > 'minimum' xs 328-- 1 329-- @ 330minimum :: (MonoFoldable mono, Ord (Element mono)) 331 => NonNull mono 332 -> Element mono 333minimum = minimumEx . toNullable 334{-# INLINE minimum #-} 335 336-- | Get the maximum element of a monomorphic container, 337-- using a supplied element ordering function. 338-- 339-- Safe version of 'maximumByEx', only works on monomorphic containers wrapped in a 340-- 'NonNull'. 341maximumBy :: MonoFoldable mono 342 => (Element mono -> Element mono -> Ordering) 343 -> NonNull mono 344 -> Element mono 345maximumBy cmp = maximumByEx cmp . toNullable 346{-# INLINE maximumBy #-} 347 348-- | Get the minimum element of a monomorphic container, 349-- using a supplied element ordering function. 350-- 351-- Safe version of 'minimumByEx', only works on monomorphic containers wrapped in a 352-- 'NonNull'. 353minimumBy :: MonoFoldable mono 354 => (Element mono -> Element mono -> Ordering) 355 -> NonNull mono 356 -> Element mono 357minimumBy cmp = minimumByEx cmp . toNullable 358{-# INLINE minimumBy #-} 359 360-- | 'fmap' over the underlying container in a 'NonNull'. 361-- 362-- @since 1.0.6.0 363 364-- ==== __Examples__ 365-- 366-- @ 367-- > let xs = 'ncons' 1 [2, 3 :: Int] 368-- > 'mapNonNull' 'show' xs 369-- 'NonNull' {toNullable = [\"1\",\"2\",\"3\"]} 370-- @ 371mapNonNull :: (Functor f, MonoFoldable (f b)) 372 => (a -> b) 373 -> NonNull (f a) 374 -> NonNull (f b) 375mapNonNull f = impureNonNull . fmap f . toNullable 376