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