{-# language
DeriveAnyClass
, DeriveFoldable
, DeriveFunctor
, DeriveGeneric
, DeriveTraversable
, DerivingStrategies
#-}
module NonEmpty
( NonEmpty(..)
, head
, tail
, toList
, zip
, zipWith
, unzip
, nonEmpty
) where
import Control.Comonad
import Control.Comonad.Hoist.Class
import Control.Monad.Zip
import Data.Foldable hiding (toList)
import Data.Functor.Apply
import Data.Semigroup.Foldable.Class
import GHC.Generics (Generic, Generic1)
import Prelude hiding (head, tail,zip,zipWith,unzip)
import qualified Data.Foldable as F
import qualified Data.List.NonEmpty as NE
data NonEmpty f a = NonEmpty a (f a)
deriving stock (Functor, Foldable, Traversable)
deriving stock (Generic, Generic1)
deriving stock (Show, Read)
deriving stock (Eq, Ord)
deriving anyclass (ComonadApply)
instance Applicative f => Applicative (NonEmpty f) where
pure x = NonEmpty x (pure x)
(<*>) = apNonEmpty (<*>)
instance Apply f => Apply (NonEmpty f) where
(<.>) = apNonEmpty (<.>)
apNonEmpty :: ()
=> (f (a -> b) -> f a -> f b)
-> NonEmpty f (a -> b)
-> NonEmpty f a
-> NonEmpty f b
apNonEmpty ap (NonEmpty f fs) (NonEmpty x xs) = NonEmpty (f x) (ap fs xs)
{-# inline apNonEmpty #-}
instance (Applicative f, Comonad f) => Comonad (NonEmpty f) where
extract = head
duplicate w@(NonEmpty _ f) = NonEmpty w (fmap pure f)
instance ComonadHoist NonEmpty where
cohoist f (NonEmpty x w) = NonEmpty x (f w)
instance (Foldable f) => Foldable1 (NonEmpty f) where
fold1 (NonEmpty a f) = fold' a f
{-# inline fold1 #-}
foldMap1 h (NonEmpty a f) = foldMap' a h f
{-# inline foldMap1 #-}
toNonEmpty (NonEmpty a f) = toNonEmpty' a f
{-# inline toNonEmpty #-}
head :: NonEmpty f a -> a
head ~(NonEmpty a _) = a
{-# inline head #-}
tail :: NonEmpty f a -> f a
tail ~(NonEmpty _ f) = f
{-# inline tail #-}
toList :: Foldable f => NonEmpty f a -> [a]
toList ~(NonEmpty a f) = a : F.toList f
{-# inline toList #-}
zip :: (MonadZip f)
=> NonEmpty f a
-> NonEmpty f b
-> NonEmpty f (a,b)
zip = zipWith (,)
{-# inline zip #-}
zipWith :: (MonadZip f)
=> (a -> b -> c)
-> NonEmpty f a
-> NonEmpty f b
-> NonEmpty f c
zipWith f ~(NonEmpty a fa) ~(NonEmpty b fb)
= NonEmpty (f a b) (mzipWith f fa fb)
{-# inline zipWith #-}
unzip :: (Functor f)
=> NonEmpty f (a,b)
-> (NonEmpty f a, NonEmpty f b)
unzip = NE.unzip
{-# inline unzip #-}
nonEmpty :: a -> f a -> NonEmpty f a
nonEmpty = NonEmpty
{-# inline nonEmpty #-}
toNonEmpty' :: (Foldable t) => a -> t a -> NE.NonEmpty a
toNonEmpty' a xs = a NE.:| F.toList xs
{-# inline toNonEmpty' #-}
foldMap' :: (Semigroup m, Foldable t) => a -> (a -> m) -> t a -> m
foldMap' z0 f = foldr ((<>) . f) (f z0)
{-# inline foldMap' #-}
fold' :: (Semigroup m, Foldable t) => m -> t m -> m
fold' z0 = foldMap' z0 id
{-# inline fold' #-}