packages feed

one-0.0.2: src/Control/One.hs

{-# OPTIONS_GHC -Wall -Werror #-}

-- |
-- Type-class abstractions for data types with a singleton view, built on
-- [lens](https://hackage.haskell.org/package/lens).
--
-- == Overview
--
-- Many data types have a natural notion of containing \"exactly one\" element.
-- A 'Data.List.NonEmpty.NonEmpty' list always has a head. An 'Data.Functor.Identity.Identity' always wraps a single
-- value. A 'Data.Set.Set' might contain exactly one element.
--
-- This library provides two parallel class hierarchies:
--
-- * __@*OneItem@ classes__ — optics to\/from the singleton /element/ of a container
-- * __@*One@ classes__ — optics to\/from the 'One' data type, which separates a
--   distinguished head element from a functorial rest
--
-- == The @One@ data type
--
-- @
-- data 'One' f a t = 'One' a (f t)
-- type 'One'' f x = 'One' f x x
-- @
--
-- @'One' f a t@ represents a value with a distinguished head @a@ and a
-- functorial rest @f t@. For example:
--
-- * @'Data.List.NonEmpty.NonEmpty' a@ is isomorphic to @'One' [] a a@
-- * @'Data.Functor.Identity.Identity' a@ is isomorphic to @'One' 'Data.Proxy.Proxy' a ()@
-- * @'Data.Text.Text'@ decomposes as @'One' ('Data.Functor.Const.Const' 'Data.Text.Text') 'Char' ()@
-- * @(x, a)@ is isomorphic to @'One' ('Data.Functor.Const.Const' x) a ()@
--
-- 'One' has instances for 'Data.Bifunctor.Bifunctor', 'Data.Bifunctor.Apply.Biapply',
-- 'Data.Biapplicative.Biapplicative', 'Data.Bifoldable.Bifoldable',
-- 'Data.Bitraversable.Bitraversable', 'Data.Semigroup.Bifoldable.Bifoldable1',
-- 'Data.Semigroup.Bitraversable.Bitraversable1', 'Data.Semigroup.Foldable.Foldable1',
-- and 'Data.Semigroup.Traversable.Traversable1'.
--
-- == @*OneItem@ classes — optics to\/from the element
--
-- @
-- 'GetterOneItem'        'ReviewOneItem'
--       |                    |
--  'HasOneItem'           'AsOneItem'
-- @
--
-- * 'GetterOneItem' — provides @'getOneItem' :: 'Control.Lens.Getter' x ('GetterOneItemElement' x)@ to
--   extract the element.
-- * 'HasOneItem' (superclass: 'GetterOneItem') — provides @'oneItem' :: 'Control.Lens.Lens'' x ('HasOneItemElement' x)@
--   to both get and set the element. A default implementation is derived from
--   'getOneItem' and 'setOneItem'.
-- * 'ReviewOneItem' — provides @'reviewOneItem' :: 'Control.Lens.Review' x ('ReviewOneItemElement' x)@ to
--   construct a singleton value from an element.
-- * 'AsOneItem' (superclass: 'ReviewOneItem') — provides @'_OneItem' :: 'Control.Lens.Prism'' x ('AsOneItemElement' x)@
--   to both construct and pattern-match singleton values. A default
--   implementation is derived from 'reviewOneItem' and 'matchOneItem'.
--
-- == @*One@ classes — optics to\/from the @One@ data type
--
-- @
-- 'GetterOne'        'ReviewOne'
--     |                |
--   'HasOne'           'AsOne'
-- @
--
-- * 'GetterOne' — provides @'getOne' :: 'Control.Lens.Getter' x ('One' f a t)@
-- * 'HasOne' (superclass: 'GetterOne') — provides @'one' :: 'Control.Lens.Lens'' x ('One' f a t)@
--   and @'rest' :: 'Control.Lens.Lens'' x (f t)@
-- * 'ReviewOne' — provides @'reviewOne' :: 'Control.Lens.Review' x ('One' f a t)@
-- * 'AsOne' (superclass: 'ReviewOne') — provides @'_One' :: 'Control.Lens.Prism'' x ('One' f a t)@.
--   A default implementation is derived from 'reviewOne' and 'matchOne'.
--
-- These use functional dependencies (@| x -> f a t@) to determine the
-- functor, head, and tail types.
--
-- == Usage
--
-- === Working with the @One@ decomposition
--
-- >>> import Control.Lens (preview, review, set, view)
-- >>> import Data.Functor.Identity (Identity(..))
-- >>> import Data.List.NonEmpty (NonEmpty(..))
-- >>> import Data.Set (Set)
-- >>> import qualified Data.Text as Text
-- >>> view one (1 :| [2, 3]) :: One [] Int Int
-- One 1 [2,3]
--
-- >>> set one (One 9 [10]) (1 :| [2, 3])
-- 9 :| [10]
--
-- >>> view rest (1 :| [2, 3])
-- [2,3]
--
-- >>> preview _One (Text.pack "hi") :: Maybe (One (Data.Functor.Const.Const Text.Text) Char ())
-- Just (One 'h' (Const "i"))
--
-- === Working with singleton elements (@*OneItem@)
--
-- >>> review reviewOneItem 7 :: [Int]
-- [7]
--
-- >>> review reviewOneItem 7 :: Set Int
-- fromList [7]
--
-- >>> preview _OneItem [7]
-- Just 7
--
-- >>> preview _OneItem [1, 2]
-- Nothing
--
-- >>> view oneItem (1 :| [2, 3])
-- 1
--
-- >>> set oneItem 9 (1 :| [2, 3])
-- 9 :| [2,3]
--
-- >>> view oneItem (Identity 7)
-- 7
--
-- == Instances
--
-- Instances are provided for a wide range of standard types including:
--
-- * __Containers__: @[]@, 'Data.List.NonEmpty.NonEmpty', 'Data.Sequence.Seq',
--   'Data.Set.Set', 'Data.Map.Map', 'Data.IntSet.IntSet', 'Data.IntMap.IntMap',
--   'Data.HashSet.HashSet', 'Data.HashMap.Strict.HashMap'
-- * __Text and bytes__: 'Data.Text.Text', @Data.Text.Lazy.Text@, @Data.Text.Short.ShortText@,
--   'Data.ByteString.ByteString' (strict, lazy, and short variants)
-- * __Maybe and Either__: 'Maybe', 'Either'
-- * __Newtypes__: 'Data.Functor.Identity.Identity', 'Data.Functor.Const.Const',
--   'Data.Semigroup.First', 'Data.Semigroup.Last', 'Data.Semigroup.Min',
--   'Data.Semigroup.Max', 'Data.Semigroup.Dual', 'Data.Semigroup.Sum',
--   'Data.Semigroup.Product', 'Data.Semigroup.WrappedMonoid',
--   'Data.Ord.Down', 'Control.Applicative.ZipList', 'GHC.Generics.Par1', 'Data.Tuple.Solo'
-- * __Tuples__: @(x, a)@
--
-- Types that always contain one element (e.g. 'Data.Functor.Identity.Identity',
-- 'Data.List.NonEmpty.NonEmpty', 'Data.Tuple.Solo') have instances for all four classes
-- in both hierarchies. Types that might contain one element (e.g. @[]@, 'Maybe',
-- 'Data.Set.Set') have instances only for the prism side ('ReviewOneItem' \/ 'AsOneItem'
-- and 'ReviewOne' \/ 'AsOne').
module Control.One (module O) where

import Control.One.AsOneItem as O
import Control.One.GetterOneItem as O
import Control.One.HasOneItem as O
import Control.One.One as O
import Control.One.ReviewOneItem as O