{-# LANGUAGE AllowAmbiguousTypes #-} {-# LANGUAGE CPP #-} {-# LANGUAGE ConstraintKinds #-} {-# LANGUAGE DeriveDataTypeable #-} {-# LANGUAGE DeriveFunctor #-} {-# LANGUAGE DeriveGeneric #-} {-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE GADTs #-} {-# LANGUAGE KindSignatures #-} {-# LANGUAGE LambdaCase #-} {-# LANGUAGE MultiParamTypeClasses #-} {-# LANGUAGE RankNTypes #-} {-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE StandaloneDeriving #-} {-# LANGUAGE TupleSections #-} {-# LANGUAGE TypeApplications #-} {-# LANGUAGE TypeInType #-} {-# LANGUAGE TypeOperators #-} {-# LANGUAGE UndecidableInstances #-} {-# LANGUAGE ViewPatterns #-} -- | -- Module : Numeric.Backprop.Tuple -- Copyright : (c) Justin Le 2018 -- License : BSD3 -- -- Maintainer : justin@jle.im -- Stability : experimental -- Portability : non-portable -- -- Canonical strict tuples (and unit) with 'Num' instances for usage with -- /backprop/. This is here to solve the problem of orphan instances in -- libraries and potential mismatched tuple types. -- -- If you are writing a library that needs to export 'BVar's of tuples, -- consider using the tuples in this module so that your library can have -- easy interoperability with other libraries using /backprop/. -- -- Because of API decisions, 'backprop' and 'gradBP' only work with things -- with 'Num' instances. However, this disallows default 'Prelude' tuples -- (without orphan instances from packages like -- ). -- -- Until tuples have 'Num' instances in /base/, this module is intended to -- be a workaround for situations where: -- -- This comes up often in cases where: -- -- (1) A function wants to return more than one value (@'BVar' s ('T2' -- a b)@ -- (2) You want to uncurry a 'BVar' function to use with 'backprop' and -- 'gradBP'. -- (3) You want to use the useful 'Prism's automatically generated by -- the lens library, which use tuples for multiple-constructor fields. -- -- Only 2-tuples and 3-tuples are provided. Any more and you should -- probably be using your own custom product types, with instances -- automatically generated from something like -- . -- -- Lenses into the fields are provided, but they also work with '_1', '_2', -- and '_3' from "Lens.Micro". However, note that these are incompatible -- with '_1', '_2', and '_3' from "Control.Lens". -- -- You can "construct" a @'BVar' s ('T2' a b)@ with functions like -- 'isoVar'. -- -- @since 0.1.1.0 -- module Numeric.Backprop.Tuple ( -- * Zero-tuples (unit) T0(..) -- * Two-tuples , T2(..) -- ** Conversions -- $t2iso , t2Tup, tupT2 -- ** Consumption , uncurryT2, curryT2 -- ** Lenses , t2_1, t2_2 -- * Three-tuples , T3(..) -- ** Conversions -- $t3iso , t3Tup, tupT3 -- ** Lenses , t3_1, t3_2, t3_3 -- ** Consumption , uncurryT3, curryT3 -- * N-Tuples , T(..) , indexT -- ** Conversions -- $tiso , tOnly, onlyT, tSplit, tAppend, tProd, prodT -- ** Lenses , tIx, tHead, tTail, tTake, tDrop -- ** Internal Utility , constT, mapT, zipT ) where import Control.DeepSeq import Control.Monad.Trans.State import Data.Bifunctor import Data.Data import Data.Kind import Data.Type.Combinator import Data.Type.Index import Data.Type.Length import Data.Type.Product import GHC.Generics (Generic) import Lens.Micro import Lens.Micro.Internal hiding (Index) import System.Random import Type.Class.Known import Type.Family.List import qualified Data.Binary as Bi #if !MIN_VERSION_base(4,11,0) import Data.Semigroup #endif -- | Unit ('()') with 'Num', 'Fractional', and 'Floating' instances. -- -- Be aware that the methods in its numerical instances are all non-strict: -- -- @ -- _ + _ = 'T0' -- 'negate' _ = 'T0' -- 'fromIntegral' _ = 'T0' -- @ -- -- @since 0.1.4.0 data T0 = T0 deriving (Show, Read, Eq, Ord, Generic, Data) -- | Strict 2-tuple with 'Num', 'Fractional', and 'Floating' instances. -- -- @since 0.1.1.0 data T2 a b = T2 !a !b deriving (Show, Read, Eq, Ord, Generic, Functor, Data, Typeable) -- | Strict 3-tuple with a 'Num', 'Fractional', and 'Floating' instances. -- -- @since 0.1.1.0 data T3 a b c = T3 !a !b !c deriving (Show, Read, Eq, Ord, Generic, Functor, Data, Typeable) -- | Strict inductive N-tuple with a 'Num', 'Fractional', and 'Floating' -- instances. -- -- It is basically "yet another HList", like the one found in -- "Data.Type.Product" and many other locations on the haskell ecosystem. -- Because it's inductively defined, it has O(n) random indexing, but is -- efficient for zipping and mapping and other sequential consumption -- patterns. -- -- It is provided because of its 'Num' instance, making it useful for -- /backproup/. Will be obsolete when 'Data.Type.Product.Product' gets -- numerical instances. -- -- @since 0.1.5.0 data T :: [Type] -> Type where TNil :: T '[] (:&) :: !a -> !(T as) -> T (a ': as) -- | @since 0.1.5.1 deriving instance ListC (Show <$> as) => Show (T as) -- | @since 0.1.5.1 deriving instance ListC (Eq <$> as) => Eq (T as) -- | @since 0.1.5.1 deriving instance (ListC (Eq <$> as), ListC (Ord <$> as)) => Ord (T as) -- | @since 0.1.5.1 deriving instance Typeable (T as) -- | @since 0.1.5.1 deriving instance Typeable T0 -- | @since 0.1.5.1 deriving instance Typeable (T2 a b) -- | @since 0.1.5.1 deriving instance Typeable (T3 a b c) instance NFData T0 instance (NFData a, NFData b) => NFData (T2 a b) instance (NFData a, NFData b, NFData c) => NFData (T3 a b c) instance ListC (NFData <$> as) => NFData (T as) where rnf = \case TNil -> () x :& xs -> rnf x `seq` rnf xs -- | @since 0.1.5.2 instance Random T0 where randomR _ = (T0,) random = (T0,) randomRs _ _ = repeat T0 randoms _ = repeat T0 randomIO = pure T0 -- | @since 0.1.5.2 instance (Random a, Random b) => Random (T2 a b) where randomR (T2 lx ly, T2 ux uy) = runState $ T2 <$> state (randomR (lx, ux)) <*> state (randomR (ly, uy)) random = runState $ T2 <$> state random <*> state random -- | @since 0.1.5.2 instance (Random a, Random b, Random c) => Random (T3 a b c) where randomR (T3 lx ly lz, T3 ux uy uz) = runState $ T3 <$> state (randomR (lx, ux)) <*> state (randomR (ly, uy)) <*> state (randomR (lz, uz)) random = runState $ T3 <$> state random <*> state random <*> state random -- TODO: optimize? -- | @since 0.1.5.1 instance Bi.Binary T0 -- | @since 0.1.5.1 instance (Bi.Binary a, Bi.Binary b) => Bi.Binary (T2 a b) -- | @since 0.1.5.1 instance (Bi.Binary a, Bi.Binary b, Bi.Binary c) => Bi.Binary (T3 a b c) instance Bifunctor T2 where bimap f g (T2 x y) = T2 (f x) (g y) instance Bifunctor (T3 a) where bimap f g (T3 x y z) = T3 x (f y) (g z) -- | Convert to a Haskell tuple. -- -- Forms an isomorphism with 'tupT2'. t2Tup :: T2 a b -> (a, b) t2Tup (T2 x y) = (x, y) -- | Convert from Haskell tuple. -- -- Forms an isomorphism with 't2Tup'. tupT2 :: (a, b) -> T2 a b tupT2 (x, y) = T2 x y -- | Convert to a Haskell tuple. -- -- Forms an isomorphism with 'tupT3'. t3Tup :: T3 a b c -> (a, b, c) t3Tup (T3 x y z) = (x, y, z) -- | Convert from Haskell tuple. -- -- Forms an isomorphism with 't3Tup'. tupT3 :: (a, b, c) -> T3 a b c tupT3 (x, y, z) = T3 x y z -- | A singleton 'T' -- -- Forms an isomorphism with 'tOnly' -- -- @since 0.1.5.0 onlyT :: a -> T '[a] onlyT = (:& TNil) -- | Extract a singleton 'T' -- -- Forms an isomorphism with 'onlyT' -- -- @since 0.1.5.0 tOnly :: T '[a] -> a tOnly (x :& _) = x -- | Uncurry a function to take in a 'T2' of its arguments -- -- @since 0.1.2.0 uncurryT2 :: (a -> b -> c) -> T2 a b -> c uncurryT2 f (T2 x y) = f x y -- | Curry a function taking a 'T2' of its arguments -- -- @since 0.1.2.0 curryT2 :: (T2 a b -> c) -> a -> b -> c curryT2 f x y = f (T2 x y) -- | Uncurry a function to take in a 'T3' of its arguments -- -- @since 0.1.2.0 uncurryT3 :: (a -> b -> c -> d) -> T3 a b c -> d uncurryT3 f (T3 x y z) = f x y z -- | Curry a function taking a 'T3' of its arguments -- -- @since 0.1.2.0 curryT3 :: (T3 a b c -> d) -> a -> b -> c -> d curryT3 f x y z = f (T3 x y z) instance Field1 (T2 a b) (T2 a' b) a a' where _1 = t2_1 instance Field2 (T2 a b) (T2 a b') b b' where _2 = t2_2 instance Field1 (T3 a b c) (T3 a' b c) a a' where _1 = t3_1 instance Field2 (T3 a b c) (T3 a b' c) b b' where _2 = t3_2 instance Field3 (T3 a b c) (T3 a b c') c c' where _3 = t3_3 instance Field1 (T (a ': as)) (T (a ': as)) a a where _1 = tIx IZ instance Field2 (T (a ': b ': as)) (T (a ': b ': as)) b b where _2 = tIx (IS IZ) instance Field3 (T (a ': b ': c ': as)) (T (a ': b ': c ': as)) c c where _3 = tIx (IS (IS IZ)) -- | Lens into the first field of a 'T2'. Also exported as '_1' from -- "Lens.Micro". t2_1 :: Lens (T2 a b) (T2 a' b) a a' t2_1 f (T2 x y) = (`T2` y) <$> f x -- | Lens into the second field of a 'T2'. Also exported as '_2' from -- "Lens.Micro". t2_2 :: Lens (T2 a b) (T2 a b') b b' t2_2 f (T2 x y) = T2 x <$> f y -- | Lens into the first field of a 'T3'. Also exported as '_1' from -- "Lens.Micro". t3_1 :: Lens (T3 a b c) (T3 a' b c) a a' t3_1 f (T3 x y z) = (\x' -> T3 x' y z) <$> f x -- | Lens into the second field of a 'T3'. Also exported as '_2' from -- "Lens.Micro". t3_2 :: Lens (T3 a b c) (T3 a b' c) b b' t3_2 f (T3 x y z) = (\y' -> T3 x y' z) <$> f y -- | Lens into the third field of a 'T3'. Also exported as '_3' from -- "Lens.Micro". t3_3 :: Lens (T3 a b c) (T3 a b c') c c' t3_3 f (T3 x y z) = T3 x y <$> f z -- | Index into a 'T'. -- -- /O(i)/ -- -- @since 0.1.5.0 indexT :: Index as a -> T as -> a indexT = flip (^.) . tIx -- | Lens into a given index of a 'T'. -- -- @since 0.1.5.0 tIx :: Index as a -> Lens' (T as) a tIx IZ f (x :& xs) = (:& xs) <$> f x tIx (IS i) f (x :& xs) = (x :&) <$> tIx i f xs -- | Lens into the head of a 'T' -- -- @since 0.1.5.0 tHead :: Lens (T (a ': as)) (T (b ': as)) a b tHead f (x :& xs) = (:& xs) <$> f x -- | Lens into the tail of a 'T' -- -- @since 0.1.5.0 tTail :: Lens (T (a ': as)) (T (a ': bs)) (T as) (T bs) tTail f (x :& xs) = (x :&) <$> f xs -- | Append two 'T's. -- -- Forms an isomorphism with 'tSplit'. -- -- @since 0.1.5.0 tAppend :: T as -> T bs -> T (as ++ bs) tAppend TNil ys = ys tAppend (x :& xs) ys = x :& tAppend xs ys infixr 5 `tAppend` -- | Split a 'T'. For splits known at compile-time, you can use 'known' to -- derive the 'Length' automatically. -- -- Forms an isomorphism with 'tAppend'. -- -- @since 0.1.5.0 tSplit :: Length as -> T (as ++ bs) -> (T as, T bs) tSplit LZ xs = (TNil, xs) tSplit (LS l) (x :& xs) = first (x :&) . tSplit l $ xs -- | Lens into the initial portion of a 'T'. For splits known at -- compile-time, you can use 'known' to derive the 'Length' automatically. -- -- @since 0.1.5.0 tTake :: forall as bs cs. Length as -> Lens (T (as ++ bs)) (T (cs ++ bs)) (T as) (T cs) tTake l f (tSplit l->(xs,ys)) = flip (tAppend @cs @bs) ys <$> f xs -- | Lens into the ending portion of a 'T'. For splits known at -- compile-time, you can use 'known' to derive the 'Length' automatically. -- -- @since 0.1.5.0 tDrop :: forall as bs cs. Length as -> Lens (T (as ++ bs)) (T (as ++ cs)) (T bs) (T cs) tDrop l f (tSplit l->(xs,ys)) = tAppend xs <$> f ys -- | Convert a 'T' to a 'Tuple'. -- -- Forms an isomorphism with 'prodT'. -- -- @since 0.1.5.0 tProd :: T as -> Tuple as tProd TNil = Ø tProd (x :& xs) = x ::< tProd xs -- | Convert a 'Tuple' to a 'T'. -- -- Forms an isomorphism with 'tProd'. -- -- @since 0.1.5.0 prodT :: Tuple as -> T as prodT Ø = TNil prodT (I x :< xs) = x :& prodT xs instance Num T0 where _ + _ = T0 _ - _ = T0 _ * _ = T0 negate _ = T0 abs _ = T0 signum _ = T0 fromInteger _ = T0 instance Fractional T0 where _ / _ = T0 recip _ = T0 fromRational _ = T0 instance Floating T0 where pi = T0 _ ** _ = T0 logBase _ _ = T0 exp _ = T0 log _ = T0 sqrt _ = T0 sin _ = T0 cos _ = T0 asin _ = T0 acos _ = T0 atan _ = T0 sinh _ = T0 cosh _ = T0 asinh _ = T0 acosh _ = T0 atanh _ = T0 instance Semigroup T0 where _ <> _ = T0 instance Monoid T0 where mempty = T0 mappend = (<>) instance (Num a, Num b) => Num (T2 a b) where T2 x1 y1 + T2 x2 y2 = T2 (x1 + x2) (y1 + y2) T2 x1 y1 - T2 x2 y2 = T2 (x1 - x2) (y1 - y2) T2 x1 y1 * T2 x2 y2 = T2 (x1 * x2) (y1 * y2) negate (T2 x y) = T2 (negate x) (negate y) abs (T2 x y) = T2 (abs x) (abs y) signum (T2 x y) = T2 (signum x) (signum y) fromInteger x = T2 (fromInteger x) (fromInteger x) instance (Fractional a, Fractional b) => Fractional (T2 a b) where T2 x1 y1 / T2 x2 y2 = T2 (x1 / x2) (y1 / y2) recip (T2 x y) = T2 (recip x) (recip y) fromRational x = T2 (fromRational x) (fromRational x) instance (Floating a, Floating b) => Floating (T2 a b) where pi = T2 pi pi T2 x1 y1 ** T2 x2 y2 = T2 (x1 ** x2) (y1 ** y2) logBase (T2 x1 y1) (T2 x2 y2) = T2 (logBase x1 x2) (logBase y1 y2) exp (T2 x y) = T2 (exp x) (exp y) log (T2 x y) = T2 (log x) (log y) sqrt (T2 x y) = T2 (sqrt x) (sqrt y) sin (T2 x y) = T2 (sin x) (sin y) cos (T2 x y) = T2 (cos x) (cos y) asin (T2 x y) = T2 (asin x) (asin y) acos (T2 x y) = T2 (acos x) (acos y) atan (T2 x y) = T2 (atan x) (atan y) sinh (T2 x y) = T2 (sinh x) (sinh y) cosh (T2 x y) = T2 (cosh x) (cosh y) asinh (T2 x y) = T2 (asinh x) (asinh y) acosh (T2 x y) = T2 (acosh x) (acosh y) atanh (T2 x y) = T2 (atanh x) (atanh y) instance (Semigroup a, Semigroup b) => Semigroup (T2 a b) where T2 x1 y1 <> T2 x2 y2 = T2 (x1 <> x2) (y1 <> y2) #if MIN_VERSION_base(4,11,0) instance (Monoid a, Monoid b) => Monoid (T2 a b) where #else instance (Semigroup a, Semigroup b, Monoid a, Monoid b) => Monoid (T2 a b) where #endif mappend = (<>) mempty = T2 mempty mempty instance (Num a, Num b, Num c) => Num (T3 a b c) where T3 x1 y1 z1 + T3 x2 y2 z2 = T3 (x1 + x2) (y1 + y2) (z1 + z2) T3 x1 y1 z1 - T3 x2 y2 z2 = T3 (x1 - x2) (y1 - y2) (z1 + z2) T3 x1 y1 z1 * T3 x2 y2 z2 = T3 (x1 * x2) (y1 * y2) (z1 + z2) negate (T3 x y z) = T3 (negate x) (negate y) (negate z) abs (T3 x y z) = T3 (abs x) (abs y) (abs z) signum (T3 x y z) = T3 (signum x) (signum y) (signum z) fromInteger x = T3 (fromInteger x) (fromInteger x) (fromInteger x) instance (Fractional a, Fractional b, Fractional c) => Fractional (T3 a b c) where T3 x1 y1 z1 / T3 x2 y2 z2 = T3 (x1 / x2) (y1 / y2) (z1 / z2) recip (T3 x y z) = T3 (recip x) (recip y) (recip z) fromRational x = T3 (fromRational x) (fromRational x) (fromRational x) instance (Floating a, Floating b, Floating c) => Floating (T3 a b c) where pi = T3 pi pi pi T3 x1 y1 z1 ** T3 x2 y2 z2 = T3 (x1 ** x2) (y1 ** y2) (z1 ** z2) logBase (T3 x1 y1 z1) (T3 x2 y2 z2) = T3 (logBase x1 x2) (logBase y1 y2) (logBase z1 z2) exp (T3 x y z) = T3 (exp x) (exp y) (exp z) log (T3 x y z) = T3 (log x) (log y) (log z) sqrt (T3 x y z) = T3 (sqrt x) (sqrt y) (sqrt z) sin (T3 x y z) = T3 (sin x) (sin y) (sin z) cos (T3 x y z) = T3 (cos x) (cos y) (cos z) asin (T3 x y z) = T3 (asin x) (asin y) (asin z) acos (T3 x y z) = T3 (acos x) (acos y) (acos z) atan (T3 x y z) = T3 (atan x) (atan y) (atan z) sinh (T3 x y z) = T3 (sinh x) (sinh y) (sinh z) cosh (T3 x y z) = T3 (cosh x) (cosh y) (cosh z) asinh (T3 x y z) = T3 (asinh x) (asinh y) (asinh z) acosh (T3 x y z) = T3 (acosh x) (acosh y) (acosh z) atanh (T3 x y z) = T3 (atanh x) (atanh y) (atanh z) instance (Semigroup a, Semigroup b, Semigroup c) => Semigroup (T3 a b c) where T3 x1 y1 z1 <> T3 x2 y2 z2 = T3 (x1 <> x2) (y1 <> y2) (z1 <> z2) #if MIN_VERSION_base(4,11,0) instance (Monoid a, Monoid b, Monoid c) => Monoid (T3 a b c) where #else instance (Semigroup a, Semigroup b, Semigroup c, Monoid a, Monoid b, Monoid c) => Monoid (T3 a b c) where #endif mappend = (<>) mempty = T3 mempty mempty mempty -- | Initialize a 'T' with a Rank-N value. Mostly used internally, but -- provided in case useful. -- -- Must be used with /TypeApplications/ to provide the Rank-N constraint. -- -- @since 0.1.5.0 constT :: forall c as. ListC (c <$> as) => (forall a. c a => a) -> Length as -> T as constT x = go where go :: forall bs. ListC (c <$> bs) => Length bs -> T bs go LZ = TNil go (LS l) = x :& go l -- | Map over a 'T' with a Rank-N function. Mostly used internally, but -- provided in case useful. -- -- Must be used with /TypeApplications/ to provide the Rank-N constraint. -- -- @since 0.1.5.0 mapT :: forall c as. ListC (c <$> as) => (forall a. c a => a -> a) -> T as -> T as mapT f = go where go :: forall bs. ListC (c <$> bs) => T bs -> T bs go TNil = TNil go (x :& xs) = f x :& go xs -- | Map over a 'T' with a Rank-N function. Mostly used internally, but -- provided in case useful. -- -- Must be used with /TypeApplications/ to provide the Rank-N constraint. -- -- @since 0.1.5.0 zipT :: forall c as. ListC (c <$> as) => (forall a. c a => a -> a -> a) -> T as -> T as -> T as zipT f = go where go :: forall bs. ListC (c <$> bs) => T bs -> T bs -> T bs go TNil TNil = TNil go (x :& xs) (y :& ys) = f x y :& go xs ys instance (Known Length as, ListC (Num <$> as)) => Num (T as) where (+) = zipT @Num (+) (-) = zipT @Num (-) (*) = zipT @Num (*) negate = mapT @Num negate abs = mapT @Num abs signum = mapT @Num signum fromInteger x = constT @Num (fromInteger x) known instance (Known Length as, ListC (Num <$> as), ListC (Fractional <$> as)) => Fractional (T as) where (/) = zipT @Fractional (/) recip = mapT @Fractional recip fromRational x = constT @Fractional (fromRational x) known instance (Known Length as, ListC (Num <$> as), ListC (Fractional <$> as), ListC (Floating <$> as)) => Floating (T as) where pi = constT @Floating pi known (**) = zipT @Floating (**) logBase = zipT @Floating logBase exp = mapT @Floating exp log = mapT @Floating log sqrt = mapT @Floating sqrt sin = mapT @Floating sin cos = mapT @Floating cos asin = mapT @Floating asin acos = mapT @Floating acos atan = mapT @Floating atan sinh = mapT @Floating sinh cosh = mapT @Floating cosh asinh = mapT @Floating asinh acosh = mapT @Floating acosh atanh = mapT @Floating atanh instance ListC (Semigroup <$> as) => Semigroup (T as) where (<>) = zipT @Semigroup (<>) instance (Known Length as, ListC (Semigroup <$> as), ListC (Monoid <$> as)) => Monoid (T as) where mempty = constT @Monoid mempty known mappend = (<>) -- | @since 0.1.5.1 instance (Known Length as, ListC (Bi.Binary <$> as)) => Bi.Binary (T as) where put = \case TNil -> pure () x :& xs -> do Bi.put x Bi.put xs get = getT known getT :: ListC (Bi.Binary <$> as) => Length as -> Bi.Get (T as) getT = \case LZ -> pure TNil LS l -> do x <- Bi.get xs <- getT l pure (x :& xs) -- | @since 0.1.5.2 instance (Known Length as, ListC (Random <$> as)) => Random (T as) where randomR (l, u) = runState (randomRT l u) random = runState (randomT known) randomRT :: (ListC (Random <$> as), RandomGen g) => T as -> T as -> State g (T as) randomRT = \case TNil -> \case TNil -> pure TNil lx :& lxs -> \case ux :& uxs -> (:&) <$> state (randomR (lx, ux)) <*> randomRT lxs uxs randomT :: (ListC (Random <$> as), RandomGen g) => Length as -> State g (T as) randomT = \case LZ -> pure TNil LS l -> (:&) <$> state random <*> randomT l -- $t2iso -- -- If using /lens/, the two conversion functions can be chained with prisms -- and traversals and other optics using: -- -- @ -- 'iso' 'tupT2' 't2Tup' :: 'Iso'' (a, b) ('T2' a b) -- @ -- $t3iso -- -- If using /lens/, the two conversion functions can be chained with prisms -- and traversals and other optics using: -- -- @ -- 'iso' 'tupT3' 't2Tup' :: 'Iso'' (a, b, c) ('T3' a b c) -- @ -- $tiso -- -- If using /lens/, the two conversion functions can be chained with prisms -- and traversals and other optics using: -- -- @ -- 'iso' 'onlyT' 'tOnly' :: 'Iso'' a (T '[a]) -- @