cassette-0.2.0: src/Text/Cassette/Lead.hs
{-# LANGUAGE RankNTypes #-}
module Text.Cassette.Lead where
import Control.Lens qualified as Lens
import Text.Cassette.Internal.Tr (Tr(..))
import Text.Cassette.Prim
-- | Nullary leads. Synonym to 'PP'.
type NullL s = forall r. K7 Tr r (s -> r)
-- | Unary leads. A lead of type @'UnL' s a@ projects/injects a component @a@
-- from/into outer type @s@.
type UnL s a = forall r. K7 Tr (a -> r) (s -> r)
-- | Binary leads. A lead of type @'BinL' s a b@ projects/injects components
-- @a@, @b@ from/into outer type @s@.
type BinL s a b = forall r. K7 Tr (a -> b -> r) (s -> r)
-- | Ternary leads. A lead of type @'TernL' s a b c@ projects/injects components
-- @a@, @b@, @c@ from/into outer type @s@.
type TernL s a b c = forall r. K7 Tr (a -> b -> c -> r) (s -> r)
-- | Quaternary leads. A lead of type @'QuaternL' s a b c d@ projects/injects
-- components @a@, @b@, @c@, @d@ from/into outer type @s@.
type QuaternL s a b c d = forall r. K7 Tr (a -> b -> c -> d -> r) (s -> r)
-- | Lift an isomorphism (see the
-- [lens](https://hackage.haskell.org/package/lens) library) to a lead.
isoL :: forall s a. Lens.Iso s s a a -> UnL s a
isoL l = K7 (Tr leadin) (Tr leadout)
where
leadin k k' s t = k (\s _ -> k' s t) s (Lens.view l t)
leadout k k' s u = k (\s _ -> k' s u) s (\x -> u (Lens.view (Lens.from l) x))
-- | Lift a prism (see [lens](https://hackage.haskell.org/package/lens) library)
-- to a lead.
prismL :: Lens.Prism s s a a -> UnL s a
prismL l = K7 (Tr leadin) (Tr leadout)
where
leadin k k' s t = case Lens.preview l t of
Nothing -> k' s t
Just x -> k (\s _ -> k' s t) s x
leadout k k' s u = k (\s _ -> k' s u) s (\x -> u (Lens.review l x))
-- | Iterates a one step construction function (resp. deconstruction) function,
-- i.e. a lead, thus obtaining a right fold (resp. unfold). The resulting lead
-- is a catamorphism on one side and an anamorpism on the other, hence the name.
-- The type of this function is the same as that of 'foldr', lifted to
-- cassettes.
catanar :: BinL b a b -> BinL b b [a]
catanar _ = error "unimplemented"
-- catanar (K7 (Tr f) (Tr f')) = K7 (Tr g) (Tr g')
-- where
-- g k k' s xs@[] z = k (\s _ -> k' s xs z) s z
-- g k k' s xs@(x:xs') z =
-- g (\k' s z -> f k (\s _ _ -> k' s z) s z x) (\s _ _ -> k' s xs z) s xs' z
-- g' k k' s z =
-- f' (\k' s z x -> g' (\k' s xs' z -> k k' s (x:xs') z) (\s _ -> k' s z x) s z) (\s _ -> k (\s _ _ -> k' s z) s [] z) s z
-- | Iterates a one step construction function (resp. deconstruction) function,
-- i.e. a lead, thus obtaining a left fold (resp. unfold). The resulting lead is
-- a catamorphism on one side and an anamorpism on the other, hence the name.
-- The type of this function is the same as that of 'foldl', lifted to
-- cassettes.
catanal :: BinL a a b -> BinL a a [b]
catanal _ = error "unimplemented"
-- catanal (K7 (Tr f) (Tr f')) = K7 (Tr g) (Tr (g' []))
-- where
-- g k k' s xs@[] z = k (\s _ -> k' s xs z) s z
-- g k k' s xs@(x:xs') z =
-- f (\k' s z -> g k (\s _ _ -> k' s z) s xs' z) (\s _ _ -> k' s xs z) s x z
-- g' xs' k k' s z =
-- f' (\k' s x z -> g' (x:xs') k (\s _ -> k' s x z) s z) (\s _ -> k (\s _ _ -> k' s z) s xs' z) s z
-- | '(:)' lead.
consL :: BinL [a] a [a]
consL = K7 (Tr leadin) (Tr leadout)
where
leadin k k' s xs@(x:xs') = k (\s _ _ -> k' s xs) s x xs'
leadin _ k' s xs = k' s xs
leadout k k' s u = k (\s _ -> k' s u) s (\x xs' -> u (x:xs'))
-- | '[]' lead.
nilL :: NullL [a]
nilL = K7 (Tr leadin) (Tr leadout)
where
leadin k k' s xs@[] = k (\s -> k' s xs) s
leadin _ k' s xs = k' s xs
leadout k k' s u = k (\s _ -> k' s u) s (u [])
-- | 'Just' lead.
justL :: UnL (Maybe a) a
justL = K7 (Tr leadin) (Tr leadout)
where
leadin k k' s mb@(Just x) = k (\s _ -> k' s mb) s x
leadin _ k' s mb = k' s mb
leadout k k' s u = k (\s _ -> k' s u) s (\x -> u (Just x))
-- | 'Nothing' lead.
nothingL :: PP (Maybe a)
nothingL = K7 (Tr leadin) (Tr leadout)
where
leadin k k' s mb@Nothing = k (\s -> k' s mb) s
leadin _ k' s mb = k' s mb
leadout k k' s u = k (\s _ -> k' s u) s (u Nothing)
-- | Construct/destruct the unit element.
unitL :: NullL ()
unitL = K7 (Tr leadin) (Tr leadout)
where
leadin k k' s t@() = k (\s -> k' s t) s
leadout k k' s u = k (\s _ -> k' s u) s (u ())
-- | Construct/destruct a pair.
pairL :: BinL (a, b) a b
pairL = K7 (Tr leadin) (Tr leadout)
where
leadin k k' s t@(x1, x2) = k (\s _ _ -> k' s t) s x1 x2
leadout k k' s u = k (\s _ -> k' s u) s (\x1 x2 -> u (x1, x2))
-- | Construct/destruct a 3-tuple.
tripleL :: TernL (a, b, c) a b c
tripleL = K7 (Tr leadin) (Tr leadout)
where
leadin k k' s t@(x1, x2, x3) = k (\s _ _ _ -> k' s t) s x1 x2 x3
leadout k k' s u = k (\s _ -> k' s u) s (\x1 x2 x3 -> u (x1, x2, x3))
-- | Construct/destruct a 4-tuple.
quadrupleL :: QuaternL (a, b, c, d) a b c d
quadrupleL = K7 (Tr leadin) (Tr leadout)
where
leadin k k' s t@(x1, x2, x3, x4) = k (\s _ _ _ _ -> k' s t) s x1 x2 x3 x4
leadout k k' s u = k (\s _ -> k' s u) s (\x1 x2 x3 x4 -> u (x1, x2, x3, x4))