| Safe Haskell | Safe |
|---|---|
| Language | Haskell2010 |
Lens.Family.Total
Contents
Description
This module lets you exhaustively pattern match on types using
Lenses, Traversals, or Prisms.
Here's an example use of this library:
import Lens.Family.Total
import Lens.Family.Stock
total :: Either Char Int -> String -- Same as:
total = _case -- total = \case
& on _Left (\c -> replicate 3 c ) -- Left c -> replicate 3 c
& on _Right (\n -> replicate n '!') -- Right n -> replicate n '!'Our total function pattern matches exhaustively on the Either type using
the _Left and _Right prisms:
>>>total (Left 'X')"XXX">>>total (Right 2)"!!"
The types ensure that the above function is total. For example, if you omit
the _Right branch:
partial :: Either Char Int -> String
partial = _case
& on _Left (\c -> replicate 3 c )... then you will get the following type error:
No instance for (Empty Int) arising from a use of ‘_case’
In the first argument of ‘(&)’, namely ‘_case’
In the expression: _case & on _Left (\ c -> replicate 3 c)
In an equation for ‘partial’:
partial = _case & on _Left (\ c -> replicate 3 c)That type error means that you didn't pattern match on the branch with the
Int.
You can also implement exhaustive pattern matching for your own data types with
Traversals or Prisms. However, this only works if
you have one type variable for each branch of your type:
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE TemplateHaskell #-}
import Control.Lens.TH
import GHC.Generics (Generic)
import Lens.Family.Total
data Example a b c = C1 a | C2 b | C3 c deriving (Generic)
makePrisms ''Example
instance (Empty a, Empty b, Empty c) => Empty (Example a b c)
example :: Example String Char Int -> String -- Same as:
example = _case -- example = \case
& on _C1 (\s -> s ) -- C1 s -> s
& on _C2 (\c -> replicate 3 c ) -- C2 c -> replicate 3 c
& on _C3 (\n -> replicate n '!') -- C3 n -> replicate n '!'There is no way to prove that the pattern match is exhaustive unless there is
a type parameter for every branch. This is because each successive pattern
match Voids out that branch's type parameter to prove that the branch no
longer needs to be handled. _case just verifies that all type parameters are
Void.
You can still write an inexhaustive pattern match so long as you provide a default:
example :: Example Int String Float -> String
example = _default "default"
& on _C2 (\s -> s)You can even pattern match using Lenses, too:
example :: (Int, Char) -> String -- Same as:
example = _case -- example = \case
& on _1 (\n -> replicate n '1') -- (n, _) -> replicate n '1'... and of course the identity lens (id) works, too:
example :: (Int, Char) -> String -- Same as:
example = _case -- example = \case
& on id (\(n, c) -> replicate n c) -- (n, c) -> replicate n cDocumentation
A type class for uninhabited types
Minimal complete definition
Nothing
Instances
| Empty Void Source # | |
Defined in Lens.Family.Total Methods impossible :: Void -> x Source # | |
| (Empty a, Empty b) => Empty (Either a b) Source # | |
Defined in Lens.Family.Total Methods impossible :: Either a b -> x Source # | |
| Empty a => Empty (a, b) Source # | |
Defined in Lens.Family.Total Methods impossible :: (a, b) -> x Source # | |
Methods
gimpossible :: f a -> x Source #
Instances
| GEmpty (V1 :: Type -> Type) Source # | |
Defined in Lens.Family.Total Methods gimpossible :: V1 a -> x Source # | |
| Empty a => GEmpty (K1 i a :: Type -> Type) Source # | |
Defined in Lens.Family.Total Methods gimpossible :: K1 i a a0 -> x Source # | |
| (GEmpty a, GEmpty b) => GEmpty (a :+: b) Source # | |
Defined in Lens.Family.Total Methods gimpossible :: (a :+: b) a0 -> x Source # | |
| GEmpty a => GEmpty (a :*: b) Source # | |
Defined in Lens.Family.Total Methods gimpossible :: (a :*: b) a0 -> x Source # | |
| GEmpty a => GEmpty (M1 i c a) Source # | |
Defined in Lens.Family.Total Methods gimpossible :: M1 i c a a0 -> x Source # | |
_case :: Empty a => a -> x Source #
Synonym for impossible, used to check if a pattern match is exhaustive
_default :: x -> a -> x Source #
Synonym for const, used to provide a default if a pattern match is
inexhaustive
on :: ((a -> Either a Void) -> s -> Either a r) -> (a -> o) -> (r -> o) -> s -> o Source #
Pattern match on a Traversal
Re-exports
Uninhabited data type
Since: base-4.8.0.0
Instances
| Eq Void | Since: base-4.8.0.0 |
| Data Void | Since: base-4.8.0.0 |
Defined in Data.Void Methods gfoldl :: (forall d b. Data d => c (d -> b) -> d -> c b) -> (forall g. g -> c g) -> Void -> c Void # gunfold :: (forall b r. Data b => c (b -> r) -> c r) -> (forall r. r -> c r) -> Constr -> c Void # dataTypeOf :: Void -> DataType # dataCast1 :: Typeable t => (forall d. Data d => c (t d)) -> Maybe (c Void) # dataCast2 :: Typeable t => (forall d e. (Data d, Data e) => c (t d e)) -> Maybe (c Void) # gmapT :: (forall b. Data b => b -> b) -> Void -> Void # gmapQl :: (r -> r' -> r) -> r -> (forall d. Data d => d -> r') -> Void -> r # gmapQr :: (r' -> r -> r) -> r -> (forall d. Data d => d -> r') -> Void -> r # gmapQ :: (forall d. Data d => d -> u) -> Void -> [u] # gmapQi :: Int -> (forall d. Data d => d -> u) -> Void -> u # gmapM :: Monad m => (forall d. Data d => d -> m d) -> Void -> m Void # gmapMp :: MonadPlus m => (forall d. Data d => d -> m d) -> Void -> m Void # gmapMo :: MonadPlus m => (forall d. Data d => d -> m d) -> Void -> m Void # | |
| Ord Void | Since: base-4.8.0.0 |
| Read Void | Reading a Since: base-4.8.0.0 |
| Show Void | Since: base-4.8.0.0 |
| Ix Void | Since: base-4.8.0.0 |
| Generic Void | |
| Semigroup Void | Since: base-4.9.0.0 |
| Exception Void | Since: base-4.8.0.0 |
Defined in Data.Void Methods toException :: Void -> SomeException # fromException :: SomeException -> Maybe Void # displayException :: Void -> String # | |
| Empty Void Source # | |
Defined in Lens.Family.Total Methods impossible :: Void -> x Source # | |
| type Rep Void | Since: base-4.8.0.0 |