one-0.0.1: src/Control/One/AsOne.hs
{-# LANGUAGE DefaultSignatures #-}
{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE PatternSynonyms #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE TypeOperators #-}
{-# OPTIONS_GHC -Wall -Werror #-}
module Control.One.AsOne where
import Control.Applicative (Const (..), ZipList (..))
import Control.Lens (Prism', preview, prism', review, view, _Just, _Right, _Wrapped)
import Control.One.ReviewOne (ReviewOne (ReviewOneItem, reviewOne))
import qualified Data.ByteString as ByteString
import qualified Data.ByteString.Lazy as LazyByteString
import qualified Data.ByteString.Short as ShortByteString
import Data.Functor.Identity (Identity (..))
import Data.HashMap.Strict (HashMap)
import qualified Data.HashMap.Strict as HashMap
import Data.HashSet (HashSet)
import qualified Data.HashSet as HashSet
import Data.Hashable (Hashable)
import Data.IntMap (IntMap)
import qualified Data.IntMap as IntMap
import Data.IntSet (IntSet)
import qualified Data.IntSet as IntSet
import Data.List.NonEmpty (NonEmpty (..))
import Data.Map (Map)
import qualified Data.Map as Map
import Data.Ord (Down (..))
import Data.Semigroup (Dual (..), First (..), Last (..), Max (..), Min (..), Product (..), Sum (..), WrappedMonoid (..))
import Data.Sequence (Seq, pattern (:<|))
import qualified Data.Sequence as Sequence
import Data.Set (Set)
import qualified Data.Set as Set
import qualified Data.Text as Text
import qualified Data.Text.Lazy as LazyText
import Data.Tuple (Solo (..))
import Data.Word (Word8)
import GHC.Generics (Par1 (..))
class (ReviewOne x) => AsOne x where
type AsOneItem x
matchOne :: x -> Maybe (AsOneItem x)
_One :: Prism' x (AsOneItem x)
default _One :: (ReviewOneItem x ~ AsOneItem x) => Prism' x (AsOneItem x)
_One = prism' (review reviewOne) matchOne
-- | >>> preview _One [7]
-- Just 7
--
-- >>> preview _One [1, 2]
-- Nothing
--
-- >>> preview _One ([] :: [Int])
-- Nothing
--
-- >>> review _One 7 :: [Int]
-- [7]
instance AsOne [a] where
type AsOneItem [a] = a
matchOne = \case
[a] -> Just a
_ -> Nothing
-- | >>> preview _One (7 :| [])
-- Just 7
--
-- >>> preview _One (1 :| [2])
-- Nothing
--
-- >>> review _One 7 :: NonEmpty Int
-- 7 :| []
instance AsOne (NonEmpty a) where
type AsOneItem (NonEmpty a) = a
matchOne = \case
a :| [] -> Just a
_ -> Nothing
-- | >>> preview _One (Sequence.singleton 7)
-- Just 7
--
-- >>> preview _One (Sequence.fromList [1, 2])
-- Nothing
--
-- >>> preview _One Sequence.empty
-- Nothing
--
-- >>> review _One 7 :: Seq Int
-- fromList [7]
instance AsOne (Seq a) where
type AsOneItem (Seq a) = a
matchOne = \case
a :<| Sequence.Empty -> Just a
_ -> Nothing
-- | >>> preview _One (Text.singleton 'a')
-- Just 'a'
--
-- >>> preview _One (Text.pack "ab")
-- Nothing
--
-- >>> preview _One Text.empty
-- Nothing
--
-- >>> review _One 'a' :: Text.Text
-- "a"
instance AsOne Text.Text where
type AsOneItem Text.Text = Char
matchOne x = case Text.uncons x of
Just (c, rest) | Text.null rest -> Just c
_ -> Nothing
-- | >>> preview _One (LazyText.singleton 'a')
-- Just 'a'
--
-- >>> preview _One (LazyText.pack "ab")
-- Nothing
--
-- >>> review _One 'a' :: LazyText.Text
-- "a"
instance AsOne LazyText.Text where
type AsOneItem LazyText.Text = Char
matchOne x = case LazyText.uncons x of
Just (c, rest) | LazyText.null rest -> Just c
_ -> Nothing
-- | >>> preview _One (ByteString.singleton 65)
-- Just 65
--
-- >>> preview _One (ByteString.pack [1, 2])
-- Nothing
--
-- >>> preview _One ByteString.empty
-- Nothing
--
-- >>> review _One 65 :: ByteString.ByteString
-- "A"
instance AsOne ByteString.ByteString where
type AsOneItem ByteString.ByteString = Word8
matchOne x = case ByteString.uncons x of
Just (w, rest) | ByteString.null rest -> Just w
_ -> Nothing
-- | >>> preview _One (LazyByteString.singleton 65)
-- Just 65
--
-- >>> preview _One (LazyByteString.pack [1, 2])
-- Nothing
--
-- >>> review _One 65 :: LazyByteString.ByteString
-- "A"
instance AsOne LazyByteString.ByteString where
type AsOneItem LazyByteString.ByteString = Word8
matchOne x = case LazyByteString.uncons x of
Just (w, rest) | LazyByteString.null rest -> Just w
_ -> Nothing
-- | >>> preview _One (ShortByteString.singleton 65)
-- Just 65
--
-- >>> preview _One (ShortByteString.pack [1, 2])
-- Nothing
--
-- >>> review _One 65 :: ShortByteString.ShortByteString
-- "A"
instance AsOne ShortByteString.ShortByteString where
type AsOneItem ShortByteString.ShortByteString = Word8
matchOne x =
if ShortByteString.length x == 1 then Just (ShortByteString.index x 0) else Nothing
-- | >>> preview _One (Map.singleton "key" (7 :: Int))
-- Just ("key",7)
--
-- >>> preview _One (Map.fromList [("a", 1), ("b", 2)] :: Map String Int)
-- Nothing
--
-- >>> review _One ("key", 7) :: Map String Int
-- fromList [("key",7)]
instance AsOne (Map k v) where
type AsOneItem (Map k v) = (k, v)
matchOne x =
if Map.size x == 1 then Just (Map.findMin x) else Nothing
-- | >>> preview _One (HashMap.singleton "key" (7 :: Int))
-- Just ("key",7)
--
-- >>> review _One ("key", 7) :: HashMap String Int
-- fromList [("key",7)]
instance (Hashable k) => AsOne (HashMap k v) where
type AsOneItem (HashMap k v) = (k, v)
matchOne x =
case HashMap.toList x of
[kv] -> Just kv
_ -> Nothing
-- | >>> preview _One (IntMap.singleton 1 7)
-- Just (1,7)
--
-- >>> preview _One (IntMap.fromList [(1, 2), (3, 4)])
-- Nothing
--
-- >>> review _One (1, 7) :: IntMap Int
-- fromList [(1,7)]
instance AsOne (IntMap v) where
type AsOneItem (IntMap v) = (Int, v)
matchOne x =
if IntMap.size x == 1 then Just (IntMap.findMin x) else Nothing
-- | >>> preview _One (Set.singleton 7)
-- Just 7
--
-- >>> preview _One (Set.fromList [1, 2])
-- Nothing
--
-- >>> review _One 7 :: Set Int
-- fromList [7]
instance AsOne (Set a) where
type AsOneItem (Set a) = a
matchOne x =
if Set.size x == 1 then Just (Set.findMin x) else Nothing
-- | >>> preview _One (HashSet.singleton 7)
-- Just 7
--
-- >>> review _One 7 :: HashSet Int
-- fromList [7]
instance (Hashable a) => AsOne (HashSet a) where
type AsOneItem (HashSet a) = a
matchOne x =
case HashSet.toList x of
[a] -> Just a
_ -> Nothing
-- | >>> preview _One (IntSet.singleton 7)
-- Just 7
--
-- >>> preview _One (IntSet.fromList [1, 2])
-- Nothing
--
-- >>> review _One 7 :: IntSet
-- fromList [7]
instance AsOne IntSet where
type AsOneItem IntSet = Int
matchOne x =
if IntSet.size x == 1 then Just (IntSet.findMin x) else Nothing
-- | >>> preview _One ("", 7 :: Int) :: Maybe Int
-- Just 7
--
-- >>> preview _One ("nonempty", 7 :: Int) :: Maybe Int
-- Nothing
--
-- >>> review _One 7 :: (String, Int)
-- ("",7)
instance (Eq a, Monoid a) => AsOne (a, b) where
type AsOneItem (a, b) = b
matchOne = \case
(a, b) -> if a == mempty then Just b else Nothing
-- | >>> preview _One (Just 7)
-- Just 7
--
-- >>> preview _One (Nothing :: Maybe Int)
-- Nothing
--
-- >>> review _One 7 :: Maybe Int
-- Just 7
instance AsOne (Maybe a) where
type AsOneItem (Maybe a) = a
matchOne =
preview _Just
{-# INLINE matchOne #-}
-- | >>> preview _One (Right 7 :: Either String Int)
-- Just 7
--
-- >>> preview _One (Left "err" :: Either String Int)
-- Nothing
--
-- >>> review _One 7 :: Either String Int
-- Right 7
instance AsOne (Either a b) where
type AsOneItem (Either a b) = b
matchOne =
preview _Right
{-# INLINE matchOne #-}
-- | >>> preview _One (Identity 7)
-- Just 7
--
-- >>> review _One 7 :: Identity Int
-- Identity 7
instance AsOne (Identity a) where
type AsOneItem (Identity a) = a
matchOne =
preview _Wrapped
{-# INLINE matchOne #-}
-- | >>> preview _One (Const 7 :: Const Int String)
-- Just 7
--
-- >>> review _One 7 :: Const Int String
-- Const 7
instance AsOne (Const a b) where
type AsOneItem (Const a b) = a
matchOne =
preview _Wrapped
{-# INLINE matchOne #-}
-- | >>> preview _One (First 7)
-- Just 7
--
-- >>> review _One 7 :: First Int
-- First {getFirst = 7}
instance AsOne (First a) where
type AsOneItem (First a) = a
matchOne =
preview _Wrapped
{-# INLINE matchOne #-}
-- | >>> preview _One (Last 7)
-- Just 7
--
-- >>> review _One 7 :: Last Int
-- Last {getLast = 7}
instance AsOne (Last a) where
type AsOneItem (Last a) = a
matchOne =
preview _Wrapped
{-# INLINE matchOne #-}
-- | >>> preview _One (WrapMonoid 7)
-- Just 7
--
-- >>> review _One 7 :: WrappedMonoid Int
-- WrapMonoid {unwrapMonoid = 7}
instance AsOne (WrappedMonoid a) where
type AsOneItem (WrappedMonoid a) = a
matchOne =
preview _Wrapped
{-# INLINE matchOne #-}
-- | >>> preview _One (Dual 7)
-- Just 7
--
-- >>> review _One 7 :: Dual Int
-- Dual {getDual = 7}
instance AsOne (Dual a) where
type AsOneItem (Dual a) = a
matchOne =
preview _Wrapped
{-# INLINE matchOne #-}
-- | >>> preview _One (Down 7)
-- Just 7
--
-- >>> review _One 7 :: Down Int
-- Down 7
instance AsOne (Down a) where
type AsOneItem (Down a) = a
matchOne =
preview _Wrapped
{-# INLINE matchOne #-}
-- | >>> preview _One (Sum 7)
-- Just 7
--
-- >>> review _One 7 :: Sum Int
-- Sum {getSum = 7}
instance AsOne (Sum a) where
type AsOneItem (Sum a) = a
matchOne =
preview _Wrapped
{-# INLINE matchOne #-}
-- | >>> preview _One (Product 7)
-- Just 7
--
-- >>> review _One 7 :: Product Int
-- Product {getProduct = 7}
instance AsOne (Product a) where
type AsOneItem (Product a) = a
matchOne =
preview _Wrapped
{-# INLINE matchOne #-}
-- | >>> preview _One (Min 7)
-- Just 7
--
-- >>> review _One 7 :: Min Int
-- Min {getMin = 7}
instance AsOne (Min a) where
type AsOneItem (Min a) = a
matchOne =
preview _Wrapped
{-# INLINE matchOne #-}
-- | >>> preview _One (Max 7)
-- Just 7
--
-- >>> review _One 7 :: Max Int
-- Max {getMax = 7}
instance AsOne (Max a) where
type AsOneItem (Max a) = a
matchOne =
preview _Wrapped
{-# INLINE matchOne #-}
-- | >>> preview _One (ZipList [7])
-- Just 7
--
-- >>> preview _One (ZipList [1, 2])
-- Nothing
--
-- >>> preview _One (ZipList ([] :: [Int]))
-- Nothing
--
-- >>> review _One 7 :: ZipList Int
-- ZipList {getZipList = [7]}
instance AsOne (ZipList a) where
type AsOneItem (ZipList a) = a
matchOne =
matchOne . view _Wrapped
{-# INLINE matchOne #-}
-- | >>> preview _One (Par1 7)
-- Just 7
--
-- >>> review _One 7 :: Par1 Int
-- Par1 {unPar1 = 7}
instance AsOne (Par1 a) where
type AsOneItem (Par1 a) = a
matchOne =
preview _Wrapped
{-# INLINE matchOne #-}
-- | >>> preview _One (MkSolo 7)
-- Just 7
--
-- >>> review _One 7 :: Solo Int
-- MkSolo 7
instance AsOne (Solo a) where
type AsOneItem (Solo a) = a
matchOne (MkSolo x) = Just x
{-# INLINE matchOne #-}